Enter an URL in a input field, display the URL preview using WordPress,PHP and Ajax

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.

  1. Using WordPress Standards
  2. Using the Core PHP Curl.
    1. 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" );
      ?>
      &lt;script&gt;
      	(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);
      &lt;/script&gt;
      <?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;
      }
      

      Result