file = __FILE__; $self->url = plugin_dir_url( $self->file ); $self->path = plugin_dir_path( $self->file ); $self->basename = plugin_basename( $self->file ); $self->includes(); $self->hooks(); //$self->registerJavaScripts(); //$self->registerCSS(); } return self::$instance; } /** * Include the dependencies. * * @since 1.0 */ private function includes() { require_once( 'includes/class.wp-rest-post.php'); require_once( 'includes/class.wp-rest-add-featured-image.php'); } /** * Register the plugins actions/filters. * * @since 1.0 */ private function hooks() { add_shortcode( 'display-posts-remote', array( __CLASS__, 'shortcode' ) ); } /** * Get the plugin's bas URL. * * @since 1.0 */ public function getURL() { return $this->url; } /** * Register the plugin's JavaScript. * * @since 1.0 */ private function registerJavaScripts() { } /** * Enqueue the plugin's JavaScript. * * @since 1.0 */ public static function enqueueJS() { } /** * Register the plugin's CSS. * * @since 1.0 */ private function registerCSS() { } /** * Enqueue the plugin's JavaScript. * * @since 1.0 */ public static function enqueueCSS() { } /** * Cache the REST response. * * @since 1.0 * * @param string $url * @param array $response * @param float|int $timeout */ protected function setCache( $url, $response, $timeout = DAY_IN_SECONDS ) { set_transient( $this->cacheKey( $url ), $response, $timeout ); } /** * Get cached REST response. * * @since 1.0 * * @param string $url * * @return array|false */ protected function getCache( $url ) { if ( is_array( $response = get_transient( $this->cacheKey( $url ) ) ) ) { return $response; } return FALSE; } /** * Clear cache. * * @since 1.0 * * @param string $url */ public function clearCache( $url ){ delete_transient( $this->cacheKey( $url ) ); } /** * Create cache key based on URL. * * @since 1.0 * * @param string $url * * @return string */ protected function cacheKey( $url ) { return md5( preg_replace( '(^https?://)', '', $url ) ); } /** * Query a remote site's posts. * * @since 1.0 * * @param array $untrusted * * @return array|WP_Error */ public function getPosts( $untrusted ) { $defaults = array( 'url' => '', 'category_id' => 0, 'per_page' => 10, 'order' => 'DESC', 'orderby' => 'date', 'cache_timeout' => DAY_IN_SECONDS, ); $atts = shortcode_atts( $defaults, $untrusted ); $atts['url'] = esc_url( filter_var( $atts['url'], FILTER_SANITIZE_URL ) ); if ( 0 >= strlen( $atts['url'] ) ) { return new WP_Error( 'invalid_url', __( 'Remote site URL must be provided.', 'display-posts-shortcode-remote' ), $atts['url'] ); } $url = trailingslashit( $atts['url'] ) . 'wp-json/wp/v2/posts'; $url = add_query_arg( '_embed' , '', $url ); if ( ! empty( $atts['category_id'] ) && ( is_array( $atts['category_id'] ) || false !== filter_var( $atts['category_id'], FILTER_VALIDATE_BOOLEAN ) ) ) { if ( is_array( $atts['category_id'] ) ) { $atts['category_id'] = implode( ',', $atts['category_id'] ); } $url = add_query_arg( 'categories', $atts['category_id'], $url ); } $url = add_query_arg( array( 'per_page' => $atts['per_page'], 'order' => $atts['order'], 'orderby' => $atts['orderby'], ), $url ); if ( 0 >= $atts['cache_timeout'] ) { $this->clearCache( $url ); } if ( FALSE === $response = $this->getCache( $url ) ) { $response = wp_safe_remote_get( $url ); if ( ! is_wp_error( $response ) && 0 < $atts['cache_timeout'] ) { /* * NOTE: cache will be saved during Gutenberg autosaves via the REST API. */ $this->setCache( $url, $response, $atts['cache_timeout'] ); } } if ( is_wp_error( $response ) ) { return $response; } $posts = json_decode( wp_remote_retrieve_body( $response ) ); if ( JSON_ERROR_NONE !== json_last_error() ) { return new WP_Error( 'invalid_response', json_last_error_msg(), $posts ); } return $posts; } /** * The shortcode default options/values. * * @since 1.0 * * @return array */ public function getDefaults() { return array( 'category_id' => '', 'content_class' => 'content', 'date_format' => '(n/j/Y)', 'include_content' => FALSE, 'include_date' => FALSE, 'include_date_modified' => FALSE, 'include_link' => TRUE, 'include_title' => TRUE, 'image_size' => 'thumbnail', 'no_posts_message' => __( 'No posts to display.', 'display-posts-shortcode-remote' ), 'order' => 'desc', 'orderby' => 'date', 'posts_per_page' => 10, 'title' => '', 'url' => '', 'wrapper' => 'ul', 'cache_timeout' => DAY_IN_SECONDS, ); } /** * Parse and sanitize the user supplied shortcode values. * * @since 1.0 * * @param array $untrusted The user defined shortcode attributes. * * @return array */ public function parseShortcodeAtts( $untrusted ) { $defaults = Display_Posts_Remote()->getDefaults(); $atts = shortcode_atts( $defaults, $untrusted, 'display-posts-remote' ); $restSupportOrderby = array( 'author', 'date', 'id', 'include', 'modified', 'parent', 'relevance', 'slug', 'include_slugs', 'title', ); $atts['category_id'] = wp_parse_id_list( $atts['category_id'] ); $atts['content_class'] = array_map( 'sanitize_html_class', ( explode( ' ', $atts['content_class'] ) ) ); $atts['date_format'] = sanitize_text_field( $atts['date_format'] ); $atts['include_content'] = self::toBoolean( $atts['include_content'] ); $atts['include_date'] = self::toBoolean( $atts['include_date'] ); $atts['include_date_modified'] = self::toBoolean( $atts['include_date_modified'] ); $atts['include_link'] = self::toBoolean( $atts['include_link'] ); $atts['include_title'] = self::toBoolean( $atts['include_title'] ); $atts['image_size'] = sanitize_key( $atts['image_size'] ); $atts['no_posts_message'] = sanitize_text_field( $atts['no_posts_message'] ); $atts['order'] = in_array( strtolower( $atts['order'] ), array( 'asc', 'desc' ) ) ? strtolower( sanitize_key( $atts['order'] ) ) : 'desc'; $atts['orderby'] = in_array( strtolower( $atts['orderby'] ), $restSupportOrderby ) ? strtolower( sanitize_key( $atts['orderby'] ) ) : 'date'; $atts['posts_per_page'] = filter_var( $atts['posts_per_page'], FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1, 'max_range' => 100, 'default' => 10, ), ) ); $atts['title'] = sanitize_text_field( $atts['title'] ); $atts['url'] = filter_var( $atts['url'], FILTER_SANITIZE_URL ); $atts['wrapper'] = sanitize_text_field( $atts['wrapper'] ); $atts['cache_timeout'] = absint( $atts['cache_timeout'] ); // Map shortcode option to REST API Parameter. $atts['per_page'] = $atts['posts_per_page']; return $atts; } /** * Callback for the `display-posts-remote` shortcode. * * @since 1.0 * * @param array $untrusted * @param string $content * @param string $tag * * @return string */ public static function shortcode( $untrusted, $content, $tag = 'display-posts-remote' ) { $self = Display_Posts_Remote(); $html = ''; $atts = $self->parseShortcodeAtts( $untrusted ); $result = $self->getPosts( $atts ); if ( is_wp_error( $result ) ) { return '