In this blog post, we will discuss and resolve the common feature, display the URL preview like Facebook and WhatsApp.
The blog post provides two methods.
- Using WordPress Standards
- Using the Core PHP Curl.
HTML Code for WordPress.
If you have an existing input field, add the following input field class attribute and add the preview output div tag.
<input type="text" class="preview-url-input"> <div id="preview-url-output"></div>
WordPress action and filter functions.
Add this code snippet to your active WordPress theme functions.php file.
add_action('wp_footer', 'url_preview_footer_js'); function url_preview_footer_js(){ $ajax_nonce = wp_create_nonce( "url-preview-ajax-security" ); ?> <script> (function ($) { 'use strict'; $('.preview-url-input').on("keyup", function() { $("#output").html(""); $("#loader").show(); var previewAjaxUrl = '<?php echo admin_url('admin-ajax.php') ?>'; var remote_url = $(this).val(); var image_html = ''; var total_images = 0; var current_image_position = 0; var data = { action: 'UrlPreviewAjax', security: '<?php echo $ajax_nonce; ?>', url: remote_url }; $.ajax({ type: 'POST', dataType: 'json', url: previewAjaxUrl, data: data, beforeSend : function () { $('#preview-url-loader').html('Processing! Please wait!!'); }, success: function (response) { console.log(response); if(response.status == 'error'){ $("#preview-url-output").html(response.msg).show(); $("#preview-url-loader").hide(); } else { if(response.image_src.length) { //image_src = response.image_src; total_images = parseInt(response.image_src.length-1); current_image_position = total_images; if(total_images>=0){ image_html = '<div class="image-preview" id="image-preview"><img src="'+response.image_src[current_image_position]+'"></div>'; } } var cotent_html = '<div class="text-data"><a class="page-title" href="'+remote_url+'" target="_blank">'+response.title+'</a><div>'+response.body+'</div>'; var responseHTML = '<div class="content-container">'+image_html + cotent_html+'</div>'; $("#preview-url-output").html(responseHTML).show(); $("#preview-url-loader").hide(); } }, error : function (jqXHR, textStatus, errorThrown) { //console.log(jqXHR, textStatus, errorThrown); $("#preview-url-output").html("Problem in extracting data from the remote URL").show(); $("#preview-url-loader").hide(); } }); }); })(jQuery); </script> <?php } add_action('wp_ajax_UrlPreviewAjax', 'ajax_get_url_preview'); function ajax_get_url_preview(){ if ( ! check_ajax_referer( 'url-preview-ajax-security', 'security', false ) ){ $returnMessage['msg'] = __('Not able to process. Trying unauthorized data access.', 'preview'); $returnMessage['status'] = 'error'; echo json_encode( $returnMessage ); wp_die(); } else { if (isset($_POST["url"]) && filter_var($_POST["url"], FILTER_VALIDATE_URL)) { $endpoint = $_POST["url"]; $response = wp_remote_get( $endpoint, array( 'method' => 'GET', ) ); $res_body = wp_remote_retrieve_body($response); // Load HTML to DOM Object $dom = new DOMDocument(); @$dom->loadHTML($res_body); // Parse DOM to get Title $nodes = $dom->getElementsByTagName('title'); $title = $nodes->item(0)->nodeValue; // Parse DOM to get Meta Description $metas = $dom->getElementsByTagName('meta'); $body = ""; $feature_img = ''; for ($i = 0; $i < $metas->length; $i ++) { $meta = $metas->item($i); if ($meta->getAttribute('name') == 'description') { $body = $meta->getAttribute('content'); } else if ($meta->getAttribute('property') == 'og:description' || $meta->getAttribute('name') == 'og:description') { $body = $meta->getAttribute('content'); } if ($meta->getAttribute('property') == 'og:image' || $meta->getAttribute('name') == 'og:image') { $feature_img = $meta->getAttribute('content'); } } // Parse DOM to get Images $image_urls = array(); $images = $dom->getElementsByTagName('img'); if($feature_img == ''){ for ($i = 0; $i < $images->length; $i ++) { $image = $images->item($i); $src = $image->getAttribute('src'); if(filter_var($src, FILTER_VALIDATE_URL)) { $image_src[] = $src; } } }else{ $image_src[] = $feature_img; } $output = array( 'title' => $title, 'image_src' => $image_src, 'body' => $body ); echo json_encode($output); wp_die(); } else { $returnMessage['msg'] = __('Not a valid URL.', 'preview'); $returnMessage['status'] = 'error'; echo json_encode( $returnMessage ); wp_die(); } } } add_action('wp_head', 'url_preview_styling' ); function url_preview_styling(){ ?> <style> #preview-url-output, #preview-url-loader { display: none; } #preview-url-output .content-container { position: relative; z-index: 1; display: grid; margin-top: 10px; column-gap: 10px; } #preview-url-output .text-data { grid-column-start: 3; } #preview-url-output .image-preview { grid-column-start: 1; } #preview-url-output .image-preview img { width: 100%; height: auto; max-width:320px; } #preview-url-output .text-data .page-title { color: #000; text-decoration: none; font-size: 1.2em; line-height: 30px; } </style> <?php }
Core PHP Curl code for Ajax response
As per blog post example. Save this code into a php file preview-url-ajax.php.
<?php if (isset($_POST["url"]) && filter_var($_POST["url"], FILTER_VALIDATE_URL)) { // Extract HTML using curl $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $_POST["url"]); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); $data = curl_exec($ch); curl_close($ch); // Load HTML to DOM Object $dom = new DOMDocument(); @$dom->loadHTML($data); // Parse DOM to get Title $nodes = $dom->getElementsByTagName('title'); $title = $nodes->item(0)->nodeValue; // Parse DOM to get Meta Description $metas = $dom->getElementsByTagName('meta'); $body = ""; $feature_img = ''; for ($i = 0; $i < $metas->length; $i ++) { $meta = $metas->item($i); if ($meta->getAttribute('name') == 'description') { $body = $meta->getAttribute('content'); } else if ($meta->getAttribute('property') == 'og:description' || $meta->getAttribute('name') == 'og:description') { $body = $meta->getAttribute('content'); } if ($meta->getAttribute('property') == 'og:image' || $meta->getAttribute('name') == 'og:image') { $feature_img = $meta->getAttribute('content'); } } // Parse DOM to get Images $image_urls = array(); $images = $dom->getElementsByTagName('img'); if($feature_img == ''){ for ($i = 0; $i < $images->length; $i ++) { $image = $images->item($i); $src = $image->getAttribute('src'); if(filter_var($src, FILTER_VALIDATE_URL)) { $image_src[] = $src; } } } else { $image_src[] = $feature_img; } $output = array( 'title' => $title, 'image_src' => $image_src, 'body' => $body ); echo json_encode($output); } else { $returnMessage['msg'] = 'Not a valid URL'; $returnMessage['status'] = 'error'; echo json_encode( $returnMessage ); } ?>
JavaScript code snippet for Jquery Ajax.
Do not forget to add jQuery CDN or local path before proceeding with this script.
(function ($) { 'use strict'; $('.preview-url-input').on("keyup", function() { $("#output").html(""); $("#loader").show(); var remote_url = $(this).val(); var image_html = ''; var total_images = 0; var current_image_position = 0; $.ajax({ url: "preview-url-ajax.php", type: "POST", data: {'url': remote_url}, dataType: "json", beforeSend : function () { $('#preview-url-loader').html('Processing! Please wait!!'); }, success: function (response) { console.log(response); if(response.status == 'error'){ $("#preview-url-output").html(response.msg).show(); $("#preview-url-loader").hide(); } else { if(response.image_src.length) { //image_src = response.image_src; total_images = parseInt(response.image_src.length-1); current_image_position = total_images; if(total_images>=0){ image_html = '<div class="image-preview" id="image-preview"><img src="'+response.image_src[current_image_position]+'"></div>'; } } var cotent_html = '<div class="text-data"><a class="page-title" href="'+remote_url+'" target="_blank">'+response.title+'</a><div>'+response.body+'</div>'; var responseHTML = '<div class="content-container">'+image_html + cotent_html+'</div>'; $("#preview-url-output").html(responseHTML).show(); $("#preview-url-loader").hide(); } }, error : function (jqXHR, textStatus, errorThrown) { //console.log(jqXHR, textStatus, errorThrown); $("#preview-url-output").html("Problem in extracting data from the remote URL").show(); $("#preview-url-loader").hide(); } }); }); })(jQuery);
Preview CSS code snippet
#preview-url-output, #preview-url-loader { display: none; } #preview-url-output .content-container { position: relative; z-index: 1; display: grid; margin-top: 10px; column-gap: 10px; } #preview-url-output .text-data { grid-column-start: 3; } #preview-url-output .image-preview { grid-column-start: 1; } #preview-url-output .image-preview img { width: 100%; height: auto; max-width:320px; } #preview-url-output .text-data .page-title { color: #000; text-decoration: none; font-size: 1.2em; line-height: 30px; }