The Sell
Twitter has become a major traffic circle on the social media thoroughfare. As any organization or social media savvy individual will tell you, if you want to be known and get heard, you should be on Twitter. That level of visibility means that when anything changes, even if it’s small, people will be sure to notice. So, when Twitter decided to release an update to the style of the ubiquitous Twitter timeline widget, a lot of people took notice, and not all in a positive way.

The Impact
Twitter, in fairness, did announce the change. But, considering that they’re no strangers to community blowback, you’d think they’d find a more reliable way to convey these updates to their users.  The update in this case removed the functionality of the ‘Auto-expand photos’ feature from the timeline widget settings. Mandating, essentially, that the timeline always expand media such as images, videos, etc in-line. This led to many sites that use the timeline widget to have their layout broken when it suddenly blew out of its expected constraints.

The Fix
As a company who both uses twitter for our own purposes as well as providing support to clients who utilize it for their sites, we became aware of the update the same way a lot of people did. Things broke. We observed several proposed solutions, but ultimately decided to come up with our own. After we performed some testing and determined that we had come up with something that worked pretty well, we decided to share it with the community. Understand that this is not tacitly or otherwise approved by Twitter, but does offer at least a short-term solution until a layout redesign can be implemented to accommodate the new output.

The Breakdown
The trick was to solve it both for the initial load of the page, and for any additional tweets that might pop in dynamically while someone sits on the page.

jQuery(‘.twitter-block’).on(‘DOMSubtreeModified propertychange’,“#twitter-widget-0”, function() {

hideTweetMedia();

});

The above section shows that we’re targeting the ID of the Twitter widget iFrame, “twitter-widget-0”, using the ‘.on’ function. Which is good for jQuery 1.7+. With earlier versions of jQuery, the following structure should be used to make use of the ‘delegate’ function.

jQuery(‘.twitter-block’).delegate(“#twitter-widget-0”,‘DOMSubtreeModified propertychange’function() {

hideTweetMedia();

});

In either case the fix is dependent on the widget being the child of a container that we’ve given a class of “twitter-block”. Which would look like this:

<div class=”twitter-block”>
<a class=”twitter-timeline” href=”path-to-twitter-account” data-widget-id=”widget-id”>Tweets by @twitter-user</a>
</div>

This next section does the real heavy lifting. First, it finds all the media elements within the timeline, then hides them. Next, it sets the height to 100%, forcing the iFrame to resize now that the media elements are hidden. Lastly, in order to make sure it will work for any tweets that are added after the page is loaded, it binds the ‘hideTweetMedia’ action to the actual list of tweets within the timeline.

var hideTweetMedia = function() {

jQuery(“.twitter-block”).find(“.twitter-timeline”).contents().find(“.timeline-Tweet-media”).css(“display”, “none”);

jQuery(“.twitter-block”).css(“height”, “100%”);

jQuery(“.twitter-block”).find(“.twitter-timeline”).contents().find(“.timeline-TweetList”).bind(‘DOMSubtreeModified propertychange’, function() {

hideTweetMedia(this);

});

}

Taken together these pieces provide a fix that solves the immediate problem of a layout being broken by a suddenly much taller element than you’re expecting.

The Wrap-Up
Whether it’s Facebook changing its “Share” service, LinkedIn updating its privacy policies, or Twitter “improving” its widgets, the one thing to keep in mind is that these services are out to solve larger problems. But the solutions they come up with are not going to be without costs to some of their existing users. When the time comes for you to pay the price, just remember that jQuery can be a cheap down-payment to the technical debt you might accrue.

UPDATE
The Revist
I was approached by someone who needed some help getting the script to work for their site. After offering some generic advice didn’t pan out, I decided to take a look at their site and see what I could do. I found that they had a not-unheard of use case. I’ve broken down the parts of the solution for them below.

The Core Assumptions
The first thing assumed in the script I’ve written is that you’re actually using jQuery on your site. The nature of the fix requires the use of the jQuery javascript library. The next thing assumed in the script is that you’re only using a single twitter widget on the page, and that the ID of that widget is “twitter-widget-0”. So, if you’re using more than one timeline on a page, this would, at best, only work for the first one.

The Multitudes
In order to solve the ‘more than one widget’ issue, I had to make some changes to the script to make it both agnostic to the ID of the widget, as well as able to target each widget individually, rather than all of them at once. That turned the first part of the script into this:

  jQuery(‘.twitter-block’).on(‘DOMSubtreeModified propertychange’,’iframe.twitter-timeline’, function(event) {
hideTweetMedia(jQuery(event.currentTarget).prop(‘id’));
});

The above script targets all of the instances of the timeline widget individually, and sends the ID to the function that handles the operations to remove images. The second part becomes:

  var hideTweetMedia = function(timelineId) {
jQuery(‘#’ + timelineId).contents().find(‘.timeline-Tweet-media’).css(‘display’, ‘none’);
jQuery(‘#’ + timelineId).contents().find(‘.timeline-TweetList’).bind(‘DOMSubtreeModified propertychange’, function() {
hideTweetMedia(timelineId);
});
}

Shown here, we’re accepting the ID of the timeline and targeting it to remove the images from that particular timeline, whatever it’s ID happens to be.

The Support
The last part of the solution for this case is to include the jQuery library in a way that won’t interfere with any other plugins or libraries that may be being used. PrototypeJS, in particular, is known to not play nicely with jQuery. We add the line to import jQuery in the footer, or the bottom of the body, so that it loads last, and we use the ‘noConflict’ call to make sure we’re not messing with anything else.

<script src=’https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js‘></script>
<script type=’text/javascript’>
jQuery.noConflict();
//whatever usage you want here, with no interference to/from other libraries
</script>

The End Result
What we have, finally, is a solution that should work for folks who aren’t currently using jQuery, and who may be using more than one twitter widget at a time.

<script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js“></script>
<script type=”text/javascript”>
jQuery.noConflict();
jQuery(document).ready( function() {
jQuery(‘.twitter-block’).on(‘DOMSubtreeModified propertychange’,’iframe.twitter-timeline’, function(event) {

hideTweetMedia(jQuery(event.currentTarget).prop(‘id’));
});
var hideTweetMedia = function(timelineId) {
console.log(jQuery(‘#’+ timelineId));
jQuery(‘#’ + timelineId).contents().find(‘.timeline-Tweet-media’).css(‘display’, ‘none’);
jQuery(‘#’ + timelineId).contents().find(‘.timeline-TweetList’).bind(‘DOMSubtreeModified propertychange’, function() {
hideTweetMedia(timelineId);
});
}
});
</script>

You still need to wrap the twitter link for each timeline widget in a div with a class of ‘twitter-block’ as shown in “The Breakdown” above, but other than that this is a one and done copy/paste solution. Drop this into the footer or bottom of the body or your site, and it should clear out any images in the timeline. One caveat is that you may need to change the quote symbols in the script if you copy and paste directly. Windows fancy quotes can cause this to not work, so you may be better off copying this into a notepad or equivalent simple text editor before trying to update your html. Also, be aware that if you’re returning a lot of tweets in a given timeline, this script can make it take longer to load. Happy webbing!