News:

Wondering if this will always be free?  See why free is better.

Main Menu

Embedding Open Graph

Started by nend, October 13, 2015, 04:00:54 PM

Previous topic - Next topic

nend

I am currently working on a project with just a few minutes into it so forth.

What I want to do is import Open Graph information. I am tired of all these embed options, search the mod site and you will find allot of YouTube BBC. Since allot of sites now days use Open Graph, including YouTube, I figured it would be allot easier just doing it this way.

My plan is to create a new BBC [embed]http://www.a_web_site.here[/embed].

This can be a fancy way of showing a link to a site or just to embed content into a site from a remote source.

Once a site is embeded the script will load the Open Graph data from the site. From there it will store it in the database so we wouldn't have to do this every time. It will also create a cache to help minimize loads if needed.

Then it will phase the data and work with it to figure out what needs to be done.

I made a concept script and is going well so forth. Here I loaded a YouTube URL. Since the data is openly available on how to embed it, all we have to do is put the pieces together.

<?php

echo phase_og_data(get_og_data('https://www.youtube.com/watch?v=_yi83kOB8ug'));

function 
get_og_data($url) {
if (filter_var($urlFILTER_VALIDATE_URL) === FALSE)
    
return;
libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML(file_get_contents($urlNULLNULL020000));
$xpath = new DOMXPath($doc);
$ogs = array();
foreach ($xpath->query('//*/meta[starts-with(@property, \'og:\')]') as $meta)
$ogs[$meta->getAttribute('property')] = $meta->getAttribute('content');
return($ogs);
}

function 
phase_og_data($data) {

return ('<div>'.(empty($data['og:site_name']) ? '' $data['og:site_name']).' - '.(empty($data['og:title']) ? '' $data['og:title']).'</div>'.(!empty($data['og:video:url']) ? '<iframe '.(empty($data['og:video:width']) ? '' 'width="'.$data['og:video:width'].'" ').(empty($data['og:video:height']) ? '' 'height="'.$data['og:video:height'].'" ').'src="'.$data['og:video:url'].'" frameborder="0" allowfullscreen></iframe>' '').'<div>'.(empty($data['og:image']) ? '' '<img style="float:left" src="'.$data['og:image'].'" />').(empty($data['og:description']) ? '' $data['og:description']).'</div>');

}


Now from that code I am going to build functins and work it into SMF as BBC.
So forth...
<?php
function get_og_data($url) {
$en_url urlencode($url);
if (filter_var($urlFILTER_VALIDATE_URL) === FALSE// validate url, will also need better security checks here.
    
return;
if(($data cache_get_data('og-info'.$en_url1800)) != null) { // check cache for data
return json_decode($data);
} else if (($data $smcFunc['db_query']('''SELECT data FROM {db_prefix}og-info WHERE url = {url} LIMIT 1' , array('url' => $enc_url))) != null) { // check database
return json_decode($data);
} else { // new site will have to load information directly
libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML(file_get_contents($urlNULLNULL020000)); //20k characters max should be enough.
$xpath = new DOMXPath($doc);
$data = array();
foreach ($xpath->query('//*/meta[starts-with(@property, \'og:\')]') as $meta)
$data[$meta->getAttribute('property')] = $meta->getAttribute('content');

// database save routine here


cache_put_data('og-info'.$en_urljson_encode($data), 1800);
return($data);
}
}

function 
phase_og_data($data) {

return ('<div>'.(empty($data['og:site_name']) ? '' $data['og:site_name']).' - '.(empty($data['og:title']) ? '' $data['og:title']).'</div>'.(!empty($data['og:video:url']) ? '<iframe '.(empty($data['og:video:width']) ? '' 'width="'.$data['og:video:width'].'" ').(empty($data['og:video:height']) ? '' 'height="'.$data['og:video:height'].'" ').'src="'.$data['og:video:url'].'" frameborder="0" allowfullscreen></iframe>' '').'<div>'.(empty($data['og:image']) ? '' '<img style="float:left" src="'.$data['og:image'].'" />').(empty($data['og:description']) ? '' $data['og:description']).'</div>');

}
?>


If you run the concept script you will notice how big YouTube says to embed the video, I will add checks in there later to scale it.

All that I am asking now is if anyone wants to provide feedback or ideas. Thank you.  :)

nend

Coming along, I want to add a allow/deny list in there next.

I added notes in there where you can add the integrate functions to the db to test it on a test site.

Code
<?php //integrate_pre_include

function get_og_data($url) {
$en_url urlencode($url);
if (filter_var($urlFILTER_VALIDATE_URL) === FALSE// validate url, will also need better security checks here.
    
return;
if(($data cache_get_data('og-info'.$en_url1800)) != null) { // check cache for data
return json_decode($datatrue);
// } else if (($data = $smcFunc['db_query']('', 'SELECT data FROM {db_prefix}og-info WHERE url = {url} LIMIT 1' , array('url' => $enc_url))) != null) { // check database
// return json_decode($data);
} else { // new site will have to load information directly
libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML(file_get_contents($urlNULLNULL020000)); //20k characters max should be enough.
$xpath = new DOMXPath($doc);
$data = array();
foreach ($xpath->query('//*/meta[starts-with(@property, \'og:\')]') as $meta)
$data[$meta->getAttribute('property')] = $meta->getAttribute('content');
// database save routine here
cache_put_data('og-info'.$en_urljson_encode($data), 1800);
return($data);
}
}

function 
phase_og_data($data) {

return ('
<div class="og-embed">
<div class="og-embed-title">
'
.(empty($data['og:site_name']) ? '' $data['og:site_name']).' - '.(empty($data['og:title']) ? '' $data['og:title']).'
</div>
'
.(!empty($data['og:video:url']) ? '<center><iframe class="og-embed-video" src="'.$data['og:video:url'].'" frameborder="0" allowfullscreen></iframe></center>' '').'
<div class="og-embed-description">
'
.(empty($data['og:image']) ? '' '<img class="og-embed-image" src="'.$data['og:image'].'" />').(empty($data['og:description']) ? '' $data['og:description']).'
</div>
</div>'
);

}

function 
og_bbc(&$bbc) { //integrate_bbc_codes

$bbc[] = array(
'tag' => 'embed',
'type' => 'unparsed_content',
'content' => '$1',
'validate' => 'og_bbc_validate',
'disabled_content' => '$1',
);
}

function 
og_bbc_validate (&$tag, &$data, &$disabled) {
$data phase_og_data(get_og_data($data));
}
?>


CSS
.og-embed {margin:2px;border:1px solid;}
.og-embed-title {font-weight:bold;padding:2px;background-color:#eee;border-bottom:1px solid;}
.og-embed-video {width:560px;height:315px;}
.og-embed-image {height:100px;width:100px;float:left;}
.og-embed-description {min-height:100px;background-color:#eee;padding:2px;border-top:1px solid;}

nend

So did a little more work to fix areas where I wasn't getting any OpenGraph information. I also added another cache which I use on my sites along with the server caching. So if you want to test for me please be sure to remove those lines in the code. Also be sure to add the hooks into the settings in the database. I left notes on where they need to be added. ;)

New code
<?php //integrate_pre_include

if (!defined('SMF')) 
die('Hacking attempt...');

function 
get_og_data($url) {

$en_url urlencode($url);
$data = array();
if (filter_var($urlFILTER_VALIDATE_URL) === FALSE// validate url, will also need better security checks here.
    
return(array('display'=>$url));
if(($data cache_get_data('og-info'.$en_url1800)) != null) { // check cache for data
return json_decode($datatrue);
} else if (($data sicache_get('og-info'.$en_url)) != null) { // check SICache
return json_decode($data);
} else { // new site will have to load information directly
libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML(file_get_contents($urlNULLNULL020000)); //20k characters max should be enough.
$xpath = new DOMXPath($doc);
foreach ($xpath->query('//*/meta[starts-with(@property, \'og:\')]') as $meta)
$data[$meta->getAttribute('property')] = $meta->getAttribute('content');
if (empty($data['og:title']))
$data['og:title'] = $xpath->query('//title')->item(0)->textContent;
if (empty($data['og:description']))
$data['og:description'] = $xpath->query('/html/head/meta[@name="description"]/@content')->item(0)->textContent;
sicache_put('og-info'.$en_urljson_encode($data), 604800);
cache_put_data('og-info'.$en_urljson_encode($data), 1800);
}
if (empty($data['og:title']))
return(array('display'=>$url));
return($data);
}

function 
phase_og_data($data) {

if (!empty($data['display']))
return('<a href="'.$data['display'].'" target="_blank">'.$data['display'].'</a>');

return ('
<div class="og-embed">
<div class="og-embed-title">
'
.(empty($data['og:site_name']) ? '' $data['og:site_name'].' - ').(empty($data['og:title']) ? '' $data['og:title']).'
</div>
'
.(!empty($data['og:video:url']) ? '<center><iframe class="og-embed-video" src="'.$data['og:video:url'].'" frameborder="0" allowfullscreen></iframe></center>' '').'
<div class="og-embed-description">
'
.(empty($data['og:image']) ? '' '<img class="og-embed-image" src="'.$data['og:image'].'" />').(empty($data['og:description']) ? '' $data['og:description']).'
</div>
</div>'
);

}

function 
og_bbc(&$bbc) { //integrate_bbc_codes

$bbc[] = array(
'tag' => 'embed',
'type' => 'unparsed_content',
'content' => '$1',
'validate' => 'og_bbc_validate',
'disabled_content' => '$1',
);
}

function 
og_bbc_validate (&$tag, &$data, &$disabled) {
$data phase_og_data(get_og_data($data));
}


I attached a preview.


nend

It looks like I am done testing here and will package this up to share with the rest of the community.

Allot of sites support og, not only fancy image embeds but a fancy way of showing links to sites with a description of the content.

Not only that but with og it supports video and audio embeds from allot of popular sites.

If you'd like to play with it before I package it, I have it installed on my site and also there is the code above which is a little different than the one I will be using in the final version.

nend

Ok, that was a frustrating hour testing of the final version. I uploaded it to my web host and kept getting errors in the cache due to json decode operations. Well problem was cloud hosting and the servers where taking a long while to update the file on all nodes. It usually takes only a few seconds for all nodes to get the right version but something going on at the DC.

I am like the script is perfect why isn't it working on my host, but was working perfect in my test environment.

nend

Haven't had a chance to package this up.

My Windoze hard drive died which I was doing this project on and haven't got back to it. My Ubuntu hard drive is still running strong so booting into that one.

Advertisement: