Tag Archives: orbital

Taking a break from Orbital

My hack-night project for a long time was Orbital Feed Reader. I’ve been slacking on it a lot recently. Especially after the election, I feel like I need to find things to work on that have a more direct impact on people that I can help.

I worked on a project called Donate the Difference  – it wasn’t as successful as I wanted it to be, though it did raise $25K for some charities. I learned a lot, and I’ll write some of that up here later. But it made it clear to me that I need to work on projects that make a bigger difference than a feed reader plugin.

I’m not certain what that is yet, but if you were hankering for updates to Orbital, that’s why they haven’t been coming. It’s open source, and I’m happy to take pull requests or turn it over if someone wants to do more with it. I just don’t want to lead folks on.

Mistakes were made, tears were shed

Orbital 0.2.2 – Mistakes Were Made

 

This is a tweak to fix some problems people told me about on the Orbital Feed Reader GitHub Issues page.

Some folks were getting a very bad experience during the install – everything goes blank – or they were able to install and then couldn’t add feeds or read feeds. Not good for a feed reader!  I traced down a problem where if you had a specific new default collation on your database, the way I initialized the database tables made everything go boom.  It’s fixed now, but it’s part of the problem of supporting a lot of different configurations without a giant automated test lab.

The other was that someone pointed out there is an improved PressThis page in the latest version of WordPress.  Everything was working, but you’d get a nudge message saying that there was a new way to use PressThis and why are you going this old way?  Updated and I think it’s a really good experience now!

I also did some cleanup and logging improvements so that I can work with folks who have problems in a better way.

MAX LAZER at the CMOM exhibit "Hello Japan!"

Orbital 0.2.1 – Secure Polyglot is out in the wild

I got a bit busy and I never did the release post for 0.2 so this is a big one with lots of features!
MAX LAZER at the CMOM exhibit "Hello Japan!"

Translations

Orbital is now translatable using the standard WordPress API mechanisms. If you’re a translator please contact me! I’d love to work with you to translate it! You can see the sample .po and .pot files under the “languages” directory in the plugin.

Blogroll as a Widget!

I’m really excited about this! One of the reasons I had an idea for this whole thing is that I was frustrated that the blogroll widget didn’t synchronize with my feed reader.  Why wouldn’t it just be a representation of what I’m actually reading?  So now that’s done! You can choose to display a link to the underlying OPML for download if you like.  I’d encourage you to do that because public OPML files online is a really good idea. I also put in a promo link but you can totally turn that off. I’m conflicted about putting that promo in because I’m not much of a self promoter – but I want to share this thing with more folks if possible.

Fast Feed Switcher

I don’t really like taking my fingers off the keyboard, so I really like keyboard shortcuts. I’ve added one more keyboard shortcut!  Type g to bring up a window that will let you go to any feed. You should be able to start typing the name of a feed and auto narrow down to whichever feed you want, then hit enter to go to it.

Security

I’ve added essential protection against cross site scripting attacks. In case someone is actively trying to mark your feeds read or import new feeds for you, they can’t do that anymore.

Bugfixes

Some folks experience the feeds stopped updating! That’s not good behavior for a feed reader – so it’s now fixed.
Some folks experienced a problem when they had multiple users and a user with non-edit permissions was added. That should be fixed now.
If you uninstalled the plugin it didn’t clean up after itself. Now Orbital is tidier and cleans up to not leave traces.

Orbital Feed Reader 0.1.9 Codenamed “BORN FREE” is out!

Last night I pushed out the final changes to uncage version 0.1.9 and get it out in the wild.
MAX LAZER tears off on his own  to explore Oregon

This version is mostly about giving you freedom. You should be able to easily import your stuff from other platforms into Orbital Feed Reader to use it. If you decide that you don’t want to use Orbital Feed Reader any more, you should have an easy way to leave. Any software that doesn’t tell you how to leave it is something you should be suspicious of.

Get Feeds IN

Share your OPML

For Feed Readers, the standard way to exchange lists of subscriptions is a standard called OPML. It’s an old format, but it’s how they all exchange lists of feeds. I’ve buffed up the OPML import to handle larger numbers of feeds. After you import the file you have a chance to look over the feeds and edit them, tag them or exclude them entirely. Hit save and they’ll all flow into the backend.

 

Get Feeds OUT

But we also don’t want Orbital to be a lobster trap for you. If you import that kind of data I also want you to be able to export that kind of data. Now Orbital is good at exporting your feeds. If you are logged in – we’ll export a file with all your public and private subscriptions and let you take that wherever you want. Some folks want to share their OPML publicly – if you aren’t logged in, hitting the same URL gives you only the public feeds. All your private stuff should stay safe!

Read Lotsa Feeds

Now that Orbital can handle tons of feeds coming in I wanted it to be easy to actually sort through them. Feed Tags now start off collapsed and you can expand them anytime by using the little twiddlers next to each. That’s a technical term. The twiddlers make it much more manageable to see 200 feeds over many subject areas.

Orbital Feed Reader 0.1.8 Codenamed “BEAUTY TREATMENT” is out!

IMG_1185

The most common feedback I’ve heard from folks on Orbital is that it’s not very good looking.  It does the job, but it isn’t a pleasure to look at.

I assume these people are all supermodels, so it looks like Orbital is doing great among the high fashion set.

I got out my scissors, called in the wardrobe department, applied polish and buffed with a chamois. This is the new smooth look, designed to blend in with the new admin themes of WordPress.

Hey, good lookin’!

 

Beauty comes in all thicknesses

Along the way, I’ve added some features – now it is responsive, cleaner and is even usable on my Galaxy S5. Check out this hot resizing action!

Future attractions and graceful aging

Coming soon are some cool things. First, I’m working on version 0.1.9, code named Born Free. It will deal with the how to leave Orbital and how to get into Orbital. I’d never want to trap you!

Second, WordPress is going to upgrade to version 4.0 soon. I’ll be getting Orbital ready for that, and the new REST API should make it easy to build a better mobile experience for Orbital.

Press for Orbital

Two new reviews for Orbital bring a smile to my face!
WordPress Plugins A-Z gave Orbital a 4/5 rating:

This is a great feed reader especially if you are doing research for a post or if you are like many people out there who write additional articles based on what they read. This make it easy to get a pull quote from an article and drop it right into a post. While the layout and functionality is a little raw in its appearance it seems to work very well and to give it a good go I added it to my secret blog site as a place to test some ranting on article and stories. And it seems to work quite well..

That’s great feedback and I feel like I do need to work on the style and appearance – it’s tough and I need help.

Jeff Chandler over at WPTavern also reviewed Orbital, comparing it to Feedly and Google Reader. It’s a lukewarm review – he doesn’t like the interface and feels like Feedly plus PressThis is find for him. Still, he’s offered to help me by looking at revamps of the interface.

How (not) to do Tagging in Angular.js

I’ve been working on getting tagging working in Orbital Feed Reader. Tagging feeds was really brilliant in Google Reader and I want that in the feed reader I use. So I’m building it.

The Setup

You can store tagging in your database a few different ways, but here’s the way I chose:

                         +----------+
      +----------+       | feed_tag |
      | feeds    |       |----------|
      |----------|       |  tag_id  +---+
      |  id      +-------+  feed_id |   |   +--------+
      |  name    |       +----------+   |   | tags   |
      |  url     |                      |   |--------|
      |  unread  |                      +---+  id    |
      +----------+                          |  name  |
                                            |        |
                                            +--------+

You’ve got feeds and tags, those have an ID number. You’ve got a table linking those by ID number. Easy.

The Goal

I wanted to be able to toggle between either a simple list of feeds or a list of tags with feeds underneath.

<script type="text/ng-template"  id='feedline.html'>
  <div class="feed" id="feed-{{feed.feed_id}}" 
    ng-class="{'is-editable': editable, 'is-selected': feed.isSelected}" 
    ng-click="select(feed)"  >
      {{feed.feed_name}} 
      <span class="feedcounter">{{feed.unread_count}}</span>
      <a ng-show="editable" ng-click="editFeed(feed)">⚙</a>
  </div>
</script>
<ul id='feeds' ng-hide="showByTags" >
  <li ng-repeat="feed in feeds" ng-include="'feedline.html'" ></li>
</ul>
<ul id='tags' ng-show="showByTags">
  <li class="tag" ng-repeat="(tag, feeds) in tags" >
    <div id="{{tag}}" ng-click="select(tag)" 
      ng-class="{'is-selected':tag.isSelected}" >
      #{{tag}} 
      <span class="feedcounter">{{tagUnreadCount(tag)}}</span> 
    </div>
    <ul>
      <li ng-repeat="feed in feeds" ng-include="'feedline.html'"></li>
    </ul>
  </li>
</ul>

My first stab at doing this was very wrong and I wanted to share that so you don’t go down that dumb path on your project.

The Wrong way to do tagging

I decided I would pull the feeds in two different ways. I would pull feeds from the database as a normal list, but then I would also pull a list of tags with feeds underneath.
This was my first mistake. Hitting the DB twice for the same data means I’m doing lots of duplication and sending lots of information over the internet (slooooow) twice. It also means keeping lists in sync which is also a code smell that means you are probably not keeping things DRY.

So I pull feeds from the db once like this:

SELECT
  feeds.id AS feed_id,
  COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
  feeds.feed_url,
  COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
  COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
  feeds.lASt_updated,
  feeds.lASt_error,
  u_feeds.private,
  SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count
FROM user_feeds AS u_feeds
INNER join feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
  AND u_feeds.owner = current_user_ID
GROUP BY feeds.id,
  feeds.feed_url,
  feeds.feed_name,
  feeds.icon_url,
  feeds.site_url,
  feeds.lASt_updated,
  feeds.lASt_error,
  u_feeds.private

And then pull feeds by tag like this:

SELECT
COALESCE(tags.name,'Untagged') AS tag,
COALESCE(tags.id, null) AS tag_id,
feeds.id AS feed_id,
COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
feeds.feed_url,
COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count
FROM user_feed_tags AS uft
INNER JOIN tags AS tags
  ON tags.id = uft.tag_id
INNER JOIN user_feeds AS u_feeds
  ON uft.user_feed_id = u_feeds.id
INNER JOIN feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
WHERE u_feeds.owner = current_user_ID
GROUP BY
feeds.id,
feeds.feed_url,
feeds.feed_name,
feeds.icon_url,
feeds.site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
tags.name

UNION
SELECT
'Untagged' AS tag,
null AS tag_id,
feeds.id AS feed_id,
COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
feeds.feed_url,
COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private,
SUM(if(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count

FROM user_feeds AS u_feeds
LEFT OUTER JOIN user_feed_tags AS uft
  ON uft.user_feed_id = u_feeds.id
INNER JOIN feeds AS feeds
  ON u_feeds.feed_id = feeds.id
LEFT OUTER JOIN user_entries AS ue
  ON ue.feed_id=feeds.id
WHERE u_feeds.owner = current_user_ID
  AND ISNULL(uft.user_feed_id)
GROUP BY
feeds.id,
feeds.feed_url,
feeds.feed_name,
feeds.icon_url,
feeds.site_url,
feeds.last_updated,
feeds.last_error,
u_feeds.private

For feeds by tag I then would use underscore.js’s excellent _.groupBy() method. It’s easy to see tags in angular using groupBy and I thought it was good enough.

It worked! Sure, it was inefficient, but I’m pragmatic – I just wanted to get this done and out the door so I could use it. No point in prematurely optmizing, right?

Next step was making sure I could show the unread count per tag. And keep it all in sync between the tags and the feeds themselves. This is when I smelled my stinky code smells. Every time I marked an entry in a feed as read I would have to search it out multiple times on multiple lists. This means this information was stored in multiple places – and it’s always good to follow the DRY principle. Don’t Repeat Yourself.

The Right(er) way to do tagging

Let’s regroup and try this again. I want to have ONE place where I pull info from my DB about a feed, and I want to only update information in one place but display it in multiple ways.

I changed it so I pull a straight list of the feeds, but use the group_concat SQL function to also pull in all the tags associated with a feed.

SELECT 
  u_feeds.id AS feed_id,
  COALESCE(u_feeds.feed_name,feeds.feed_name ) AS feed_name,
  feeds.feed_url, 
  COALESCE(u_feeds.icon_url, feeds.icon_url ) AS icon_url,
  COALESCE(u_feeds.site_url, feeds.site_url ) AS site_url,
  feeds.last_updated,
  feeds.last_error,
  u_feeds.private,
  SUM(IF(COALESCE(ue.isRead,1)=0,1,0)) AS unread_count,
  GROUP_CONCAT(DISTINCT COALESCE(tags.name,'Untagged')) as tags
FROM $user_feeds AS u_feeds
INNER JOIN $feeds AS feeds
  ON u_feeds.feed_id = feeds.id
  AND u_feeds.owner =  $current_user->ID.
LEFT OUTER JOIN $user_entries AS ue
  ON ue.feed_id=feeds.id
LEFT OUTER JOIN $user_feed_tags uft
  ON uft.user_feed_id = u_feeds.id
LEFT OUTER JOIN $tags tags
  ON uft.tag_id = tags.id
GROUP BY 
  feed_id,
  feed_url,
  feed_name,
  icon_url,
  site_url,
  last_updated,
  last_error,
  private

When I want to show a list of feeds I can just go with the same solution I had before.
But when I want to group by tags I can apply a couple of interesting tricks to solve this for me.

    refresh : function refresh(callback){
  _isLoading = true;
  $http.get(opts.ajaxurl + '?action=orbital_get_feeds')
  .success( function( data ){
    //Here is our simple feed list
    _feeds= data;

    //Now lets get a list of all the unique tags in those feeds
    var taga = _.unique(_.pluck(_feeds, 'tags').join().split(","));

    //For each tag, lets build up a list of the feeds that have that tag
    _.each(taga, function(tag){
      _tags[tag] = _.filter(_feeds,function(feed){
                      return _.contains(feed.tags.split(","),tag);
                    });
    })
    _isLoading = false;
    //Should we do some extra work?
    if(callback){
      callback(_feeds);
    }
  });
},

What’s going on there?
I want to get an array of all my unique tags, so first thing I do, I use _.pluck() to give me an array of the tags element of each feed.
This gives me:

[
  ["art,gifs"],
  ["art"],
  ["Untagged"],
  ["gifs"],
  ["Untagged"],
  ["Untagged"],
]

Then I join() those together (the default join is with a comma):

"art,gifs,art,Untagged,gifs,Untagged,Untagged"

I split(“,”) that on commas:

["art","gifs","art","Untagged","gifs","Untagged","Untagged"]

And finally we just grab the _.unique() values:

["art","gifs","Untagged"]

So now we have a list of the tags for our feeds – how exciting! Let’s build a list of the feeds for each of these tags.
So, for _.each() tag in our list of tags we go back to our list of feeds and _.filter() it – we want only a feed where the feed.tags _.contains() the tag.

Why’s this so much better? Well – if we update the `unread_count` for a feed or change the name of a feed – it updates the underlying object. That means your change percolates up automatically through angular databinding to every part of your UI. No more keeping lots of lists in sync.

And now I’ve bored even myself to death with this so I guess that’s it.