Search code examples
phpwordpresswpml

How to pass parameters to add_feed in an OOP singleton


I struggle creating separate page feeds (list of URLs) in each language when WPML is active.

The plan is to have different feed names for each language, such as feed_name_en or feed_name_fr.

I wrote the following function that iterates through each available language on the site and should output a feed for each language containing only the pages in the particular language.

I found other examples that show how to pass parameters within add_action using closures. (eg. add_action('init', function() use($param) { some_out_of_scope_function($param) } )

But in my function I am getting the following error:

Object of class Closure could not be converted to string in

I have the suspicion that it is because I am using OOP to encapsule the function in an array add_feed( $feedname, array( $this, ... ) ). But I have no idea how to work around this.

How shall I approach this?

$feedname = 'feed_name'; 

private function createLanguageFeeds(){

    foreach($this->wpml_languages as $lang){

        // add the lang to the feed name. example: feed_name_en
        $feedname = $this->feedname . '_' . $lang;

        // making sure that the feed is created
        if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
            $wp_rewrite->feeds[] = $feedname;
            flush_rewrite_rules( FALSE );
        }

        add_feed( $feedname, array( $this, function() use ($lang) {$this->create_page_feed($lang);} ) );
    }
}

private function create_page_feed($lang){
    // echo pages
}

Solution

  • If you're using PHP 5.4 or newer, you can just pass the closure with the $lang parameter to the add_feed() function and $this will retain the reference to the object:

    add_feed( $feedname, function() use ($lang) {$this->create_page_feed($lang);} );
    

    Note that your create_page_feed() method needs to be public so WordPress can access it:

    public function create_page_feed($lang){
        // echo pages
    }
    

    (see What is the difference between public, private, and protected? for more details.)

    Here's a tested & working demo plugin that registers a feed using the Singleton pattern:

    <?php
    /**
     * Plugin Name:       Singleton RSS Feed
     * Plugin URI:        https://cabrerahector.com
     * Description:       A demo RSS feed built using the Singleton pattern.
     * Version:           1.0.0
     * Author:            Hector Cabrera
     * Author URI:        https://cabrerahector.com/
     * License:           GPL-2.0+
     * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
     * Text Domain:       singleton-rss-feed
     * Domain Path:       /languages
     */
    
    class Singleton_RSS_Feed
    {
        /**
         * The unique instance of the plugin.
         *
         * @var Singleton_RSS_Feed
         */
        private static $instance;
    
        /**
         * Gets an instance of our plugin.
         *
         * @return Singleton_RSS_Feed
         */
        public static function get_instance()
        {
            if (null === self::$instance) {
                self::$instance = new self();
            }
    
            return self::$instance;
        }
    
        /**
         * Constructor.
         */
        private function __construct()
        {
            // Actions
            add_action('init', array($this, 'createFeed'));
        }
    
        /**
         * Register the feed.
         */
        public function createFeed()
        {
            global $wp_rewrite;
    
            $feedname = 'some_rrs_feed';
            $lang = 'en';
    
            // Making sure that the feed is created
            if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
                $wp_rewrite->feeds[] = $feedname;
                flush_rewrite_rules( FALSE );
            }
    
            add_feed( $feedname, function() use ($lang) {$this->renderFeed($lang);} );
        }
    
        /**
         * Renders the feed.
         *
         * @param string $lang
         */
        public function renderFeed($lang)
        {
            header( 'Content-Type: application/rss+xml' );
            ?>
            <xml version="1.0" encoding="UTF-8">
            <rss version="2.0">
                <channel><title>RSS Feed in <?php echo $lang; ?> language</title></channel>
            </rss>
            <?php
        }
    }
    
    $Singleton_RSS_Feed = Singleton_RSS_Feed::get_instance();
    

    The feed will be available here: https://www.example.com/feed/some_rrs_feed.