Google News considerations

You’ll notice a few of these suggestions either aren’t practical, or conflict with other suggestions. You’ll also notice the supporting documentation is for fixing errors with Google News listings. We have noticed that adhering to these when possible produces good results, so that’s why I’m calling attention to them.

Images

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=13369

  • Make sure that your images are fairly large in size, at least 60 pixels by 60 pixels. (only applies to main article image)
  • Use images that have reasonable aspect ratios.
  • Ensure that your images are inline.
  • Ensure that your clickable images link to a URL with a .jpg or .jpeg extension.
  • Place your images near their respective article titles.
  • Label your images with well-written captions.

Article snippets

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=70752&topic=2523198&ctx=topic

  • To give users a preview of an article before clicking on it, Google News displays its first few sentences on our homepage and in search results. To determine which text to include, our crawler looks at each article’s code for body text near the headline of that article.
  • We also recommend clearly differentiating the text that makes up your articles’ author bylines and date information from the text of your articles’ first sentences. Ideally, we will only show the first few sentences of your articles under their headlines in Google News.

Article date

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=70871&topic=2523198&ctx=topic

  • Place a clear date and time for each of your articles in between the article’s title and the article’s text in a separate line of HTML. This should help our crawler correctly identify the publication date for your article.
  • Make sure to provide us with the date when the article first appeared on your site.

General

Just putting it here for reference.

Debugging WordPress: Find Slow Filters and Actions

English: WordPress Logo

This is one of the ways I diagnose performance issues within WordPress, specifically “hey this site is slow, what can we do to speed it up?”  Whereas a callgrind file gives you a look into the whole callstack of your script, the point of this is to profile actions and filters in WordPress.

It does require that you make some changes to core files.  This is not meant to be something that you use in production, nor is it meant to be something you run all the time.  This is for “spring cleaning” your site, and/or tracking down general slowness.

The code between “// @custom start” and “// @custom end” is what you will be adding.  I am not including line numbers because they change frequently with the version of WordPress.

index.php

Put this at the top of index.php, before any other code.

class Pmc_Debug
{
    protected static $_threshold_to_hide = 0.1;

    public static function get_threshold_to_hide() {
        return static::$_threshold_to_hide;
    }

    public static function set_threshold_to_hide( $time ) {
        static::$_threshold_to_hide = (float) $time;
    }

    public static function record_action( $name ) {
        $backtrace = debug_backtrace(false);
        if ( ! isset($backtrace[2]['args']) ) {
             return;
        }

        foreach ( $backtrace[2]['args'] as &$arg ) {
            $arg = ( is_string($arg) ) ? stripslashes($arg) : $arg;
        }
        $GLOBALS['pmc_action_timer'][microtime()][] = array(
            'name' => $name,
            'backtrace' => var_export($backtrace[2], true),
        );
    }

    public static function print_recorded_actions() {
        ?>
        <hr />
        <div style="padding: 10px; background-color: white; color: black; white-space: pre; text-align: left;">
        <pre>
        <?php
        $timetotals = array();
        $break = '<hr />';
        $eol = '<br />';
        $detail_list = $eol . $eol . $break . $eol . $eol;
        $detail_list .= 'Detail action list.' . $eol;
        if ( static::get_threshold_to_hide() > 0.0 ) {
            $detail_list .= 'Hiding items faster than ' . static::get_threshold_to_hide() . ' seconds.' . $eol;
        }
        $detail_list .= $eol . $break . $eol;

        reset($GLOBALS['pmc_action_timer']);
        $previous_item = array('timestamp' => array('sec' => 0.0, 'usec' => 0.0), 'items' => array());
        do {
            if ( ! isset( $timestamp ) ) {
                $timestamp = microtime();
            }
            if ( ! isset( $items ) ) {
                $items = array();
            }

            list($usec, $sec) = explode(" ", $timestamp);
            $sec = (float) $sec;
            $usec = (float) $usec;
            $timestamp_float = $sec + $usec;

            if ( $timestamp && ! isset($start_time) ) {
                $start_time = $timestamp_float;
            } else {
                $end_time = $timestamp_float;
            }

            if ( empty($previous_items['items']) ) {
                $diff = 0.0;
                $previous_items['items'][] = array('name' => 'nothing', 'backtrace' => '');
            } else {
                $diff = $timestamp_float - ( $previous_items['timestamp']['sec'] + $previous_items['timestamp']['usec'] );
            }

            if ( $diff > static::get_threshold_to_hide() ) {
                $previous = array();
                if ( ! empty($previous_items['items']) ) {
                    foreach ( $previous_items['items'] as $previous_item ) {
                        $previous[] = $previous_item['name'];
                    }
                }
                foreach ( $items as $item ) {
                    $detail_list .= $eol . round($diff, 3) . ' seconds between starting ' . implode(', ', $previous) . ' and starting ' . $item['name'] . $eol;
                    if ( ! empty($previous_items['items']) ) {
                        foreach ( $previous_items['items'] as $previous_item ) {
                            $detail_list .= $previous_item['backtrace'] . $eol;
                        }
                    }
                    $detail_list .= $item['backtrace'] . $eol;
                }
            }
            foreach ( $items as $key => $item ) {
                $timetotals[$item['name']][] = $diff;
            }

            $previous_items['timestamp']['sec'] = $sec;
            $previous_items['timestamp']['usec'] = $usec;
            $previous_items['items'] = $items;
        } while ( list($timestamp, $items) = each($GLOBALS['pmc_action_timer']) );
        $detail_list .= $eol . $break . $eol;

        $summary_list = $eol . $eol . $break . $eol . $eol;
        $summary_list .= 'Action overview: aggregate totals.' . $eol;
        if ( static::get_threshold_to_hide() > 0.0 ) {
            $summary_list .= 'Hiding items faster than ' . static::get_threshold_to_hide() . ' seconds.' . $eol;
        }
        $summary_list .= $eol . $break . $eol;

        do {
            $total_time = 0.0;
            if ( isset($times) ) {
                foreach ( $times as $time ) {
                    $total_time += $time;
                }
            }
            if ( $total_time > static::get_threshold_to_hide() ) {
                $summary_list .= $tag . ' took approximately ' . round($total_time, 3) . ' seconds' . $eol;
            }
        } while ( list($tag, $times) = each($timetotals) );
        $summary_list .= $eol . $break . $eol;
        if ( $end_time < $start_time ) {
            $end_time = $start_time;
        }
        echo 'Request took ' . ( $end_time - $start_time ) . ' seconds from start to finish.' . $eol;
        echo $summary_list;
        echo $detail_list;
        ?>
        </pre>
        </div>
        <?php
    }
}

Pmc_Debug::record_action('bootup');

wp-includes/plugin.php

In this file, look for the functions below and add the lines between “@custom start” and “@custom end”.  Basically, they go at the top of all the functions where filters are applied and actions are called.

function do_action($tag, $arg = '') {
   global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function do_action_ref_array($tag, $args) {
   global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function apply_filters($tag, $value) {
   global $wp_filter, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function apply_filters_ref_array($tag, $args) {
   global $wp_filter, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end

wp-content/themes/my-theme/footer.php

Here is the code that outputs the results.  This goes anywhere after the wp_footer() function, but it’s easiest just to put it before the closing </html> tag.

Pmc_Debug::record_action('done');
Pmc_Debug::print_recorded_actions();

WordPress JS/CSS development cachebuster

Find yourself constantly battling browser cache when developing a script in WordPress?

This snippet will always give you a fresh copy of all the scripts and styles loaded via wp_enqueue_script() and wp_enqueue_style():

function pmc_dev_cachebuster( $src ) {
	return add_query_arg( 'ver', time(), $src );
}
add_filter( 'style_loader_src', 'pmc_dev_cachebuster' );
add_filter( 'script_loader_src', 'pmc_dev_cachebuster' );

Integrating InAppSettingsKit with Storyboard, UITabBarController, and ARC

I love the concept of InAppSettingsKit.  While it’s possible to make your own settings view and hook up all your own buttons, I like the simplicity of installing a “plugin” — just copy over the files, hook it up to a view, and be done with it.

I’m using the iOS 5 SDK with a Storyboarded app, using a Tab Bar, and I was able to integrate it pretty simply after a trip to Google got me on the right track:

1) Created my Settings.bundle, including NSUserDefaultsDidChangeNotification observers as described in the Apple Settings bundle documentation.  The AppPrefs sample app helped here (specifically with the observers).

2) Copied the InAppSettingsKit directories (not the sample app) into my project.

3) Made sure I had all the necessary Apple frameworks:

  • MessageUI Framework
  • UIKit Framework
  • CoreGraphics Framework
  • Foundation Framework

MessageUI was the only one I needed to add.  Project > Targets > MyApp > Build Phases > Link Binary With Libraries and click the + icon to add any that are missing.

Before adding it, I was getting this horrible error:

missing required architecture i386 in file
Undefined symbols:
  "_OBJC_CLASS_$_MFMailComposeViewController"

The nature of the error message was completely alien to me, but — again — thank you, Internet.

4) In Storyboard editor, I added a new Navigation Controller and Table View Controller.
4a) I deleted the view controller that came along for the ride when I dragged the new navigation controller to my storyboard.
4b) I linked the navigation controller to my tab bar controller, then linked the navigation controller to the table view controller (control+click and drag).
4c) I selected the Table View in the table view controller and changed the Style of the prototype content to “Grouped”.
4d) I changed the controller class to IASKAppSettingsViewController.

Et voila, it compiled and worked. With this method I didn’t need to add any custom controllers or views; just the InAppSettingsKit files and linked a new table view to the main IASK controller.

Also worth noting: since I’m using ARC in my project, I opted for an ARC-compatible fork of InAppSettingsKit. See the ticket on Github. I used tibr’s fork.

Related:

Implementing New Relic Real User Monitoring in Magento

A few months ago, New Relic introduced Real User Monitoring.  It natively supports WordPress and Drupal as of the time of this writing.  By “natively supports”, I mean you can just turn it on in the New Relic control panel and your web servers will start automatically injecting it into your pages’ head.  Real User Monitoring works with any web app, however — you just have to manually add the code yourself.

Here’s how you add it to a Magento theme template. Continue reading