Skip to content

Instantly share code, notes, and snippets.

@vanpariyar
Created April 29, 2021 06:21
Show Gist options
  • Save vanpariyar/da369014a449e379f472421187f943a6 to your computer and use it in GitHub Desktop.
Save vanpariyar/da369014a449e379f472421187f943a6 to your computer and use it in GitHub Desktop.
caching the widget on the html file from the API and increase site speed

Caching widget in HTML file so we can direclty call from the wp-content folder

this will improve the speed of the site

we are storing the response in the Wp-content folder, there are also a cron job that reflect changes on the server

<?php

/**
 * Adds Widget_Top_Article_Poc_Portrait widget.
 */
class Widget_Top_Article_Poc_Portrait extends WP_Widget {
    const REV_ENGINE_TOP_ARTICLE_API = '<Add Your API>';
    public $article_count = 5;

    /**
     * Register widget with WordPress.
     */
    public function __construct() {
        parent::__construct(
            'top_article_poc_portrait', // Base ID
            'Top Article Poc Portrait', // Name
            array( 'description' => __( 'Prtrait Widget for TOP Article Poc Portrait Layout', 'twenty-seventeen-child' ), ) // Args
        );
        add_action( 'wp_enqueue_scripts', function(){
            wp_localize_script('application-script', 'portraitWidgetChachedUrl', array( 
                'url'=> get_site_url().'/wp-content/uploads/widget-html/widget-portrait.html',
            ) );
        } );
        add_action( 'rest_api_init', array( $this, 'create_html_for_widget' ) );
        add_action('top_article_event_cron_hourly', array($this,'request_curl'));
    }

    /**
     * Front-end display of widget.
     *
     * @see WP_Widget::widget()
     *
     * @param array $args     Widget arguments.
     * @param array $instance Saved values from database.
     */
    public function widget( $args, $instance ) {
        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title'] );

        $number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
        $this->article_count = $number;

        echo $before_widget;
        if ( ! empty( $title ) ) {
            echo $before_title . $title . $after_title;
        } ?>
        <div class="top_articles_poc_portrait" data-count="<?= $number; ?>">
            <div class="ajax-loading-image" style="display: block !important;">
                <span id="loadingCircle">
                    <span id="outerCircle1"></span>
                    <span id="innerCircle"></span>
                </span>
            </div>
        </div>
        <?php
        echo $after_widget;
    }

    /**
     * Back-end widget form.
     *
     * @see WP_Widget::form()
     *
     * @param array $instance Previously saved values from database.
     */
    public function form( $instance ) {

        $title = isset( $instance[ 'title' ] ) ? $instance[ 'title' ] : __( 'New title', 'twenty-seventeen-child' );
        $number    = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;

        ?>
        <p>
            <label for="<?php echo $this->get_field_name( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
        </p>
        <p>
            <label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of Articles to show:' ); ?></label>
            <input class="tiny-text" id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="number" step="1" min="1" value="<?php echo $number; ?>" size="3" />
        </p>
        <?php
    }

    /**
     * Sanitize widget form values as they are saved.
     *
     * @see WP_Widget::update()
     *
     * @param array $new_instance Values just sent to be saved.
     * @param array $old_instance Previously saved values from database.
     *
     * @return array Updated safe values to be saved.
     */
    public function update( $new_instance, $old_instance ) {
        $instance              = $old_instance;
        $instance['title']     = sanitize_text_field( $new_instance['title'] );
        $instance['number']    = (int) $new_instance['number'];

        // Generating HTML file on Changes of article Number
        $this->article_count = $instance['number'];
        $this->create_html_file( $instance['number'] );

        return $instance;
    }

    /**
     * Make rest api call to generate html widget.
     */

    public function request_curl(){
        $domainName = $_SERVER['HTTP_HOST'].'/';
        $xml = file_get_contents("http://".$domainName."wp-json/static/html/top_article_widget_portrait");
    }

    /**
     * Get HTML markup for the article
     */
    public function GetTopArticleMarkup( $articleCount = 6 ){
        if( $_POST['count'] ) {
            $articleCount = $_POST['count'];
        }
        $articleMarkup = $this->get_article_markup($articleCount);
        $this->write_to_html_file($articleMarkup);
        exit;
    }

    /**
     * Get The data From the Rev Engine api
     * @param int $size
     * @return false|mixed
     *
     * Note: This function has transient that save data For One Hour.
     */
    public function get_top_articles( $size = 5 ){
        $request_url = self::REV_ENGINE_TOP_ARTICLE_API.'?size='.$size;
        $request = '';

        $set_article = get_transient('top_article_poc_portrait' );

        if( empty( $set_article ) || ( count( $set_article ) != $this->article_count )  ){
            $set_article = array();
            $request = wp_remote_get( $request_url );
            if ( is_wp_error( $request ) ) {
                $cached_articles = get_option('maverick_top_article_poc_portrait');
                if( $cached_articles ){
                    return $cached_articles;
                } else {
                    return false;
                }
            }

            $response  = json_decode( wp_remote_retrieve_body( $request ) );
            foreach( $response as $article ){
                $set_article[] = $article->post_id;
            }
            set_transient('top_article_poc_portrait', $set_article, HOUR_IN_SECONDS );
            update_option( 'maverick_top_article_poc_portrait', $set_article );
        }
        return( $set_article );
    }

    /**
     * Get HTML Markup From the Post Ids
     * This Function Generates HTML For the Top Article
     *
     * @param int $size
     */
    public function get_article_markup( $size = 5 ) {

        $top_articles = $this->get_top_articles( $size );
        
        if ( count($top_articles) ) : 
            ob_start();
            ?>
            <div class="top-articles-poc">
                <div class="top-articles-container">
                    <?php

                    global $post;
                    foreach( $top_articles as $key => $postId ) :
                        $post = get_post($postId);
                        if( $post ):
                            setup_postdata($post);

                            $isSponsor = has_term('sponsor', 'flag', $postId);

                            $backgroundImg = wp_get_attachment_image_src(get_post_thumbnail_id($postId), 'medium');
                            $postUrl = get_permalink($postId);
                            $authorId = $post->post_author;
                            if (empty($backgroundImg[0])) {
                                $imgUrl = getAuthorImageUrl($authorId);
                            } else {
                                $imgUrl = $backgroundImg[0];
                            }
                            ?>
                            <div class="list-item <?= (($isSponsor)? 'sponsored' : ''); ?>">
                                <a class="article-<?php echo $key?>" href="<?= $postUrl; ?>?utm_source=top_reads_widget_portrait">
                                    <div class="media">
                                        <div class="row">
                                            <div class="col-md-4 col-sm-4 col-xs-4">
                                                <div class="media-left" style="background-image: url('<?= $imgUrl; ?>');">
                                                </div>
                                            </div>
                                            <div class="col-md-8 col-sm-8 col-xs-8">
                                                <div class="media-body">
                                                    <?php getCustomLabel($postId, get_post_type($postId), $isSponsor); ?>
                                                    <h1><?= get_the_title($postId); ?></h1>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </a>
                            </div>
                        <?php endif; ?>
                    <?php endforeach; wp_reset_postdata(); wp_reset_query(); ?>
                </div>
            </div>
        <?php endif;
        return ob_get_clean();
    }

    public function write_to_html_file( $posts ){
        // $data = json_encode( $posts );
        $data = $posts;
        $widgetFilePath = 'widget-html';
        $upload_dir = wp_get_upload_dir(); // set to save in the /wp-content/uploads folder
        $file_name = 'widget-portrait.html';
        if (!file_exists($upload_dir['basedir'].'/'.$widgetFilePath)) {
            mkdir($upload_dir['basedir'].'/'.$widgetFilePath, 0777, true);
        }
        $save_path = $upload_dir['basedir'] . '/widget-html/' . $file_name;

        $f = fopen($save_path, "w"); //if json file doesn't gets saved, comment this and uncomment the one below
        //$f = @fopen( $save_path , "w" ) or die(print_r(error_get_last(),true)); //if json file doesn't gets saved, uncomment this to check for errors
        fwrite($f, $data);
        fclose($f);
    }

    public function create_html_file( $request ) {
        $this->GetTopArticleMarkup(  $this->article_count );
        $message = array(
            "type" => "sucess"
        );
        return rest_ensure_response( $message );
    }

    /**
     * This function is where we register our routes for our example endpoint.
     */
    public function create_html_for_widget() {
        // Here we are registering our route for a collection of products and creation of products.
        register_rest_route( 'static/html', '/top_article_widget_portrait', array(
            array(
                // By using this constant we ensure that when the WP_REST_Server changes, our readable endpoints will work as intended.
                'methods'  => WP_REST_Server::READABLE,
                // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
                'callback' => array( $this,'create_html_file'),
            ),
        ) );
    }

} // class Widget_Top_Article_Poc_Portrait

//Remove the cron if the clsss does not exists
if( ! class_exists( 'Widget_Top_Article_Poc_Portrait' ) ) {
    wp_clear_scheduled_hook( 'top_article_event_cron_hourly' );
}

if (! wp_next_scheduled ( 'top_article_event_cron_hourly' )) {
    wp_schedule_event( time(), 'hourly', 'top_article_event_cron_hourly' );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment