23

I'm trying to create and manipulate the Pin It button after page load. When i change the button properties with js, it should be rerendered to get the functionality of pinning dynamically loaded images. So, does Pinterest have any method like Facebook's B.XFBML.parse() function?

Thanks...

onur
  • 395
  • 1
  • 3
  • 8

13 Answers13

48

Just add data-pin-build attribute to the SCRIPT tag:

<script defer
  src="//assets.pinterest.com/js/pinit.js"
  data-pin-build="parsePinBtns"></script>

That causes pinit.js to expose its internal build function to the global window object as parsePinBtns function.

Then, you can use it to parse links in the implicit element or all of the links on the page:

// parse the whole page
window.parsePinBtns();

// parse links in #pin-it-buttons element only
window.parsePinBtns(document.getElementById('pin-it-buttons'));

Hint: to show zero count just add data-pin-zero="1" to SCRIPT tag.

Styx
  • 9,863
  • 8
  • 43
  • 53
  • 5
    It's awesome! How did you know about that? – Mikhail Jan 15 '14 at 14:51
  • 2
    This is a much more straight forward way of accomplishing what the accepted answer does. Great work, Styx! – creativetim Jan 20 '14 at 17:29
  • Works, but things to make sure of: **1.** Pinterest script must be called like this first in the page. If it has been loaded without it, then another instance of loading it may not make the build function exposed. **2.** Pinterest script removes this script tag and puts in pinit_main.js instead. During the process it checks for the **first** pinit.js script tag if it has data-pin-build attribute, and if so it uses it. **3.** Uncompressed pinit_main.js is [here](https://github.com/pinterest/widgets/blob/190f65d11f7b33d7b65fa5a8aafb2c71bd01f4e6/pinit.js#L976) – Firsh - justifiedgrid.com Feb 09 '14 at 23:30
  • 2
    I love this solution. Why is it so hard to find this kind of information on the Pinterest documentation web site? – Hewins Apr 29 '14 at 22:32
  • Simple and working solution. Can't find any info about this on the pin-it page of their developer documentation : https://developers.pinterest.com/pin_it/ I would really like to know where this tip is coming from. – Clemorphy Jun 05 '14 at 13:38
  • Awesome solution! Worked perfectly for me. I can't believe this function hook is still undocumented in 2016! – wuworkshop Nov 23 '16 at 07:49
  • Just wanted to add that there's a GitHub issue comment that mentions this undocumented function hook. https://github.com/pinterest/widgets/issues/13#issuecomment-27737036 – wuworkshop Jan 03 '17 at 01:56
14

The best way to do this:

  1. Remove the iframe of the Pin It button you want to manipulate
  2. Append the html for the new button manipulating it as you wish
  3. Realod their script - i.e. using jQuery:

    $.ajax({ url: 'http://assets.pinterest.com/js/pinit.js', dataType: 'script', cache:true});
    
Carlo Mallone
  • 326
  • 2
  • 5
  • This works for me and I prefer it since it doesn't require maintaining local Javascript to stay in sync with whatever Pinterest may do in the future. – DavidJ Apr 15 '13 at 17:51
  • I used this in an infinite scroll situation and all I needed to do was do the ajax line after loading any new content. Works like a charm! – Kevin Beal Jul 24 '13 at 21:52
9

To render a pin-it button after a page has loaded you can use:

<a href="..pin it link.." id="mybutton" class="pin-it-button" count-layout="none">
    <img border="0" src="//assets.pinterest.com/images/PinExt.png" width="43" height="21" title="Pin It" />
</a>
<script>
    var element = document.getElementById('mybutton');
    (function(x){ for (var n in x) if (n.indexOf('PIN_')==0) return x[n]; return null; })(window).f.render.buttonPin(element);
</script>

Assuming of course the assets.pinterest.com/js/pinit.js is already loaded on the page. The render object has some other useful methods like buttonBookmark, buttonFollow, ebmedBoard, embedPin, embedUser.

Tsanyo Tsanev
  • 91
  • 1
  • 1
4

I built on Derrek's solution (and fixed undeclared variable issue) to make it possible to dynamically load the pinterest button, so it can't possibly slow down load times. Only tangentially related to the original question but I thought I'd share anyway.

at end of document:

<script type="text/javascript">
addPinterestButton = function (url, media, description) {
    var js, href, html, pinJs;
    pinJs = '//assets.pinterest.com/js/pinit.js';
    //url = escape(url);
    url = encodeURIComponent(url);
    media = encodeURIComponent(media);
    description = encodeURIComponent(description);
    href = 'http://pinterest.com/pin/create/button/?url=' + url + '&media=' + media + '&description=' + description;
    html = '<a href="' + href + '" class="pin-it-button" count-layout="vertical"><img border="0" src="http://assets.pinterest.com/images/PinExt.png" title="Pin It" /></a>';
    $('#pinterestOption').html(html);

    //add pinterest js
    js = document.createElement('script');
    js.src = pinJs;
    js.type = 'text/javascript';
    document.body.appendChild(js);
}
</script>

in document ready function:

addPinterestButton('pageURL', 'img', 'description');//replace with actual data

in your document where you want the pinterest button to appear, just add an element with the id pinterestOption, i.e.

<div id="pinterestOption"></div>

hope that helps someone!

Viktor
  • 117
  • 1
  • 4
Jay Paroline
  • 2,487
  • 1
  • 22
  • 27
3

I rewrote the Pinterest button code to support the parsing of Pinterest tags after loading AJAX content, similar to FB.XFBML.parse() or gapi.plusone.go(). As a bonus, an alternate JavaScript file in the project supports an HTML5-valid syntax.

Check out the PinterestPlus project at GitHub.

Mike Kibbel
  • 1,961
  • 2
  • 12
  • 5
3

The official way to do this is by setting the "data-pin-build" attribute when loading the script:

<script defer="defer" src="//assets.pinterest.com/js/pinit.js" data-pin-build="parsePins"></script>

Then you can render your buttons dynamically like so:

// render buttons inside a scoped DOM element
window.parsePins(buttonDomElement);

// render the whole page
window.parsePins();

There is also another method on this site which lets you render them in JavaScript without the script tag.

Kamo
  • 232
  • 2
  • 4
3

Here's what I did.

First I looked at pinit.js, and determined that it replaces specially-marked anchor tags with IFRAMEs. I figured that I could write javascript logic to get the hostname used by the src attribute on the generated iframes.

So, I inserted markup according to the normal recommendations by pinterest, but I put the anchor tag into an invisible div.

<div id='dummy' style='display:none;'>
<a href="http://pinterest.com/pin/create/button/?
    url=http%3A%2F%2Fpage%2Furl
    &media=http%3A%2F%2Fimage%2Furl" 
   class="pin-it-button" count-layout="horizontal"></a>
</div>
<script type="text/javascript" src="//assets.pinterest.com/js/pinit.js">
</script>

Then, immediately after that, I inserted a script to slurp up the hostname for the pinterest CDN, from the injected iframe.

//
// pint-reverse.js
//
// logic to reverse-engineer pinterest buttons.
//
// The standard javascript module from pinterest replaces links to
// http://pinterest.com/create/button with links to some odd-looking
// url based at cloudfront.net. It also normalizes the URLs.
//
// Not sure why they went through all the trouble. It does not work for
// a dynamic page where new links get inserted.  The pint.js code
// assumes a static page, and is designed to run "once" at page creation
// time.
//
// This module spelunks the changes made by that script and
// attempts to replicate it for dynamically-generated buttons.
//

pinterestOptions = {};

(function(obj){

    function spelunkPinterestIframe() {
        var iframes = document.getElementsByTagName('iframe'),
            k = [], iframe, i, L1 = iframes.length, src, split, L2;

        for (i=0; i<L1; i++) {
            k.push(iframes[i]);
        }
        do {
            iframe = k.pop();
            src = iframe.attributes.getNamedItem('src');
            if (src !== null) {
                split = src.value.split('/');
                L2 = split.length;
                obj.host = split[L2 - 2];
                obj.script = split[L2 - 1].split('?')[0];
                //iframe.parentNode.removeChild(iframe);
            }
        } while (k.length>0);
    }

    spelunkPinterestIframe();

}(pinterestOptions));

Then,

function getPinMarkup(photoName, description) {
    var loc = document.location,
        pathParts = loc.pathname.split('/'),
        pageUri = loc.protocol + '//' + loc.hostname + loc.pathname,
        href = '/' + pathToImages + photoName,
        basePath = (pathParts.length == 3)?'/'+pathParts[1]:'',
        mediaUri = loc.protocol+'//'+loc.hostname+basePath+href,
        pinMarkup;

    description = description || null;

    pinMarkup = '<iframe class="pin-it-button" ' + 'scrolling="no" ' +
        'src="//' + pinterestOptions.host + '/' + pinterestOptions.script +
        '?url=' + encodeURIComponent(pageUri) +
        '&media=' + encodeURIComponent(mediaUri);

    if (description === null) {
        description = 'Insert standard description here';
    }
    else {
        description = 'My site - ' + description;
    }

    pinMarkup += '&description=' + encodeURIComponent(description);
    pinMarkup += '&title=' + encodeURIComponent("Pin this " + tagType);
    pinMarkup += '&layout=horizontal&count=1">';
    pinMarkup += '</iframe>';
    return pinMarkup;
}

And then use it from jQuery like this:

    var pinMarkup = getPinMarkup("snap1.jpg", "Something clever here");
    $('#pagePin').empty(); // a div...
    $('#pagePin').append(pinMarkup);
Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • I didn't test the script, but it seems that passing pageUri, mediaUri and description directly through the getPinMarkup will work for me until pinterest adds its own function. – onur Mar 21 '12 at 22:17
  • cloudfront is an AWS thing that will store images in the cloud. They did it probably because they use that service. – Kevin Beal Jul 24 '13 at 21:42
2

Try reading this post http://dgrigg.com/blog/2012/04/04/dynamic-pinterest-button/ it uses a little javascript to replace the pinterest iframe with a new button and then reloads the pinit.js file. Below is the javascript to do the trick

refreshPinterestButton = function (url, media, description) {
    var js, href, html, pinJs;
    url = escape(url);
    media = escape(media);
    description = escape(description);
    href = 'http://pinterest.com/pin/create/button/?url=' + url + '&media=' + media + '&description=' + description;
    html = '<a href="' + href + '" class="pin-it-button" count-layout="horizontal"><img border="0" src="http://assets.pinterest.com/images/PinExt.png" title="Pin It" /></a>';
    $('div.pin-it').html(html);

    //remove and add pinterest js
    pinJs = $('script[src*="assets.pinterest.com/js/pinit.js"]');
    pinJs.remove();
    js = document.createElement('script');
    js.src = pinJs.attr('src');
    js.type = 'text/javascript';
    document.body.appendChild(js);
}
Derrick Grigg
  • 141
  • 1
  • 4
2

Here is what i did.. A slight modification on @Derrick Grigg to make it work on multiple pinterest buttons on the page after an AJAX reload.

refreshPinterestButton = function () {
    var url, media, description, pinJs, href, html, newJS, js;
    var pin_url;
    var pin_buttons = $('div.pin-it a');
    pin_buttons.each(function( index ) {
        pin_url = index.attr('href');
        url = escape(getUrlVars(pin_URL)["url"]);
        media = escape(getUrlVars(pin_URL)["media"]);
        description = escape(getUrlVars(pin_URL)["description"]);
        href = 'http://pinterest.com/pin/create/button/?url=' + url + '&media=' + media + '&description=' + description;
        html = '<a href="' + href + '" class="pin-it-button" count-layout="horizontal"><img border="0" src="http://assets.pinterest.com/images/PinExt.png" title="Pin It" /></a>';
        index.parent().html(html);
    });

    //remove and add pinterest js
    pinJs = '//assets.pinterest.com/js/pinit.js';
    js = $('script[src*="assets.pinterest.com/js/pinit.js"]');
    js.remove();
    js = document.createElement('script');
    js.src = pinJs;
    js.type = 'text/javascript';
    document.body.appendChild(js);
}

});


function getUrlVars(pin_URL)
{
    var vars = [], hash;
    var hashes = pin_URL.slice(pin_URL.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}
1

Their pinit.js file, referenced in their "Pin it" button docs, doesn't expose any globals. It runs once and doesn't leave a trace other than the iframe it creates.

You could inject that file again to "parse" new buttons. Their JS looks at all anchor tags when it is run and replaces ones with class="pin-it-button" with their iframe'd button.

Ross Allen
  • 43,772
  • 14
  • 97
  • 95
0

I tried to adapt their code to work the same way (drop in, and forget about it), with the addition that you can make a call to Pinterest.init() to have any "new" buttons on the page (eg. ajax'd in, created dynamically, etc.) turned into the proper button.

Project: https://github.com/onassar/JS-Pinterest Raw: https://raw.github.com/onassar/JS-Pinterest/master/Pinterest.js

onassar
  • 3,313
  • 7
  • 36
  • 58
0

As of June 2020, Pinterest updated the pin js code to v2. That's why data-pin-build might not work on <script defer="defer" src="//assets.pinterest.com/js/pinit.js" data-pin-build="parsePins"></script>

Now it works on pinit_v2.js <script async defer src="//assets.pinterest.com/js/pinit_v2.js" data-pin-build="parsePins"></script>

0

this works fine for me: http://www.mediadevelopment.no/projects/pinit/ It picks up all data on click event

pete
  • 1