Script Tutorials

<!--Tutorials for Web Developers -->
  • Rss Feed
  • Email Updates
  • Script Tutorials on Twitter
  • Script Tutorials on Facebook
  • Script Tutorials on Google+
  • Script Tutorials on LinkedIn
  • HTML/CSS
    • Game Development →
    • Menus →
    • Templates →
    • CSS3 tutorials →
  • HTML5
  • jQuery
  • PHP
  • JS
  • Res
    • Infographic →
    • jQuery plugin roundups →
    • HTML5 stuff →
    • Mobile →
    • Other →
  • XSLT
  • Deals
Manuals

How to create Pinterest-like script – step 5

Date: 10th Jan 2013 Author: admin 21 Comments
Posted in: AJAX, HTML/CSS, HTML5, JavaScript, jQuery, MySQL, PHP |Tags: like, pins, Pinterest, repin, search

Tweet
How to create Pinterest-like script - step 5

How to create Pinterest-like script – step 5

Today – the first article in 2013. We are about to finish our Pinterest like script. In our fifth lesson I prepared next things: like and repin functionality and search. As you know, ‘like’ is a kind of a rating system. In our script – any logged member can rate any certain photo (to like it) once a hour (it is a protection system against cheating). If you like a photo and want to add it to your profile – you can click ‘repin’ button. This will add a copy of this photo for you (actually – only a new record to database). As for the search – everything is easy: we prepared this search bar long ago, but it has not worked before. I added this functionality today. We are going to publish updated sources of our script in our lesson. If you are ready – let’s start.

It is the very time to try our updated demonstration and download the source package here:

Live Demo
download in package

Step 1. SQL

In order to implement like counter and repin functionality we have to expand our `pd_photos` table.

CREATE TABLE IF NOT EXISTS `pd_photos` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `title` varchar(255) default '',
  `filename` varchar(255) default '',
  `owner` int(11) NOT NULL,
  `when` int(11) NOT NULL default '0',
  `comments_count` int(11) NOT NULL default '0',
  `repin_id` int(11) NOT NULL default '0',
  `repin_count` int(11) NOT NULL default '0',
  `like_count` int(11) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

If you want only update your existed table, please execute only this small SQL:

ALTER TABLE `pd_photos`
 ADD `repin_id` int(11) NOT NULL default '0',
 ADD `repin_count` int(11) NOT NULL default '0',
 ADD `like_count` int(11) NOT NULL default '0';

Finally, I prepared one new SQL table to keep likes:

CREATE TABLE IF NOT EXISTS `pd_items_likes` (
  `l_id` int(11) NOT NULL AUTO_INCREMENT ,
  `l_item_id` int(12) NOT NULL default '0',
  `l_pid` int(12) NOT NULL default '0',
  `l_when` int(11) NOT NULL default '0',
  PRIMARY KEY (`l_id`),
  KEY `l_item_id` (`l_item_id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;

Step 2. PHP

I decided to display search result at our ‘index.php’ page, we need to make few minor changes here. Here is updated version:

index.php

require_once('classes/CMySQL.php');
require_once('classes/CMembers.php');
require_once('classes/CPhotos.php');

// get login data
list ($sLoginMenu, $sExtra) = $GLOBALS['CMembers']->getLoginData();

// get search keyword (if provided)
$sSearchParam = strip_tags($_GET['q']);

// get all photos
$sPhotos = $GLOBALS['CPhotos']->getAllPhotos(0, $sSearchParam);

if ($sSearchParam) {
    $sExtra .= '<h2 class="pname">Search results for <strong>'.$sSearchParam.'</strong></h2>';
}

// draw common page
$aKeys = array(
    '{menu_elements}' => $sLoginMenu,
    '{extra_data}' => $sExtra,
    '{images_set}' => $sPhotos
);
echo strtr(file_get_contents('templates/index.html'), $aKeys);

Now, as you remember, we use ‘service.php’ file to perform various service methods. Please review our updated version (where I added possibilities to work with ‘like’ and ‘repin’ buttons:

service.php

require_once('classes/CMySQL.php');
require_once('classes/CMembers.php');
require_once('classes/CPhotos.php');
require_once('classes/CComments.php');

if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
    $GLOBALS['CMembers']->registerProfile();
}

$i = (int)$_GET['id'];

if ($_GET && $_GET['get'] == 'comments') {
    header('Content-Type: text/html; charset=utf-8');
    echo $GLOBALS['Comments']->getComments($i);
    exit;
}
if ($_POST) {
    header('Content-Type: text/html; charset=utf-8');
    if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
        switch($_POST['add']) {
            case 'comment':
                echo $GLOBALS['Comments']->acceptComment(); exit;
                break;
            case 'like':
                echo $GLOBALS['CPhotos']->acceptLike(); exit;
                break;
            case 'repin':
                echo $GLOBALS['CPhotos']->acceptRepin(); exit;
                break;
        }
    }
    echo '<h3>Please login first</h3>';
    exit;
}

if (! $i) { // if something is wrong - relocate to error page
    header('Location: error.php');
    exit;
}

$aPhotoInfo = $GLOBALS['CPhotos']->getPhotoInfo($i);
$aOwnerInfo = $GLOBALS['CMembers']->getProfileInfo($aPhotoInfo['owner']);

$sOwnerName = ($aOwnerInfo['first_name']) ? $aOwnerInfo['first_name'] : $aOwnerInfo['email'];
$sPhotoTitle = $aPhotoInfo['title'];
$sPhotoDate = ($aPhotoInfo['repin_id'] == 0) ? 'Uploaded on ' : 'Repinned on ';
$sPhotoDate .= $GLOBALS['CPhotos']->formatTime($aPhotoInfo['when']);

$sFolder = 'photos/';
$sFullImgPath = $sFolder . 'f_' . $aPhotoInfo['filename'];
$aSize = getimagesize($sFullImgPath); // get image info
$iWidth = $aSize[0];
$iHeight = $aSize[1];

// repin possibility to logged members
$iLoggId = (int)$_SESSION['member_id'];
$sActions = ($iLoggId && $aPhotoInfo['owner'] != $iLoggId) ? '<a href="#" class="button repinbutton" onclick="return repinPhoto(this);">Repin</a>' : '';

?>
<div class="pin bigpin" bpin_id="<?= $i ?>">
    <div class="owner">
        <a href="#" class="button follow_button">Follow</a>
        <a class="owner_img" href="profile.php?id=<?= $aOwnerInfo['id'] ?>">
            <img alt="<?= $sOwnerName ?>" src="images/avatar.jpg" />
        </a>
        <p class="owner_name"><a href="profile.php?id=<?= $aOwnerInfo['id'] ?>"><?= $sOwnerName ?></a></p>
        <p class="owner_when"><?= $sPhotoDate ?></p>
    </div>
    <div class="holder">
        <div class="actions">
            <?= $sActions ?>
        </div>
        <a class="image" href="#" title="<?= $sPhotoTitle ?>">
            <img alt="<?= $sPhotoTitle ?>" src="<?= $sFullImgPath ?>" style="width:<?= $iWidth ?>px;height:<?= $iHeight ?>px;" />
        </a>
    </div>

    <p class="desc"><?= $sPhotoTitle ?></p>

    <div class="comments"></div>

    <script>
    function submitCommentAjx() {
        $.ajax({
          type: 'POST',
          url: 'service.php',
          data: 'add=comment&id=' + <?= $i ?> + '&comment=' + $('#pcomment').val(),
          cache: false,
          success: function(html){
            if (html) {
              $('.comments').html(html);
              $(this).colorbox.resize();
            }
          }
        });
    }
    function repinPhoto(obj) {
        var iPinId = $(obj).parent().parent().parent().attr('bpin_id');
        $.ajax({
          url: 'service.php',
          type: 'POST',
          data: 'add=repin&id=' + iPinId,
          cache: false,
          success: function(res){
            window.location.href = 'profile.php?id=' + res;
          }
        });
        return false;
    }
    </script>
    <form class="comment" method="post" action="#">
        <textarea placeholder="Add a comment..." maxlength="255" id="pcomment"></textarea>
        <button type="button" class="button" onclick="return submitCommentAjx()">Comment</button>
    </form>
</div>

Next updated file is the main Photos class:

classes/CPhotos.php

/*
* Photos class
*/
class CPhotos {

    // constructor
    function CPhotos() {
    }

    // get all photos
    function getAllPhotos($iPid = 0, $sKeyPar = '') {

        // prepare WHERE filter
        $aWhere = array();
        if ($iPid) {
            $aWhere[] = "`owner` = '{$iPid}'";
        }
        if ($sKeyPar != '') {
            $sKeyword = $GLOBALS['MySQL']->escape($sKeyPar);
            $aWhere[] = "`title` LIKE '%{$sKeyword}%'";
        }
        $sFilter = (count($aWhere)) ? 'WHERE ' . implode(' AND ', $aWhere) : '';

        $sSQL = "
            SELECT *
            FROM `pd_photos`
            {$sFilter}
            ORDER BY `when` DESC
        ";
        $aPhotos = $GLOBALS['MySQL']->getAll($sSQL);

        $sPhotos = '';
        $sFolder = 'photos/';
        foreach ($aPhotos as $i => $aPhoto) {

            $iPhotoId = (int)$aPhoto['id'];
            $sFile = $aPhoto['filename'];
            $sTitle = $aPhoto['title'];
            $iCmts = (int)$aPhoto['comments_count'];

            $iLoggId = (int)$_SESSION['member_id'];
            $iOwner = (int)$aPhoto['owner'];
            $iRepins = (int)$aPhoto['repin_count'];
            $iLikes = (int)$aPhoto['like_count'];
            $sActions = ($iLoggId && $iOwner != $iLoggId) ? '<a href="#" class="button repinbutton">Repin</a><a href="#" class="button likebutton">Like</a>' : '';

            $aPathInfo = pathinfo($sFolder . $sFile);
            $sExt = strtolower($aPathInfo['extension']);

            $sImages .= <<<EOL
<!-- pin element {$iPhotoId} -->
<div class="pin" pin_id="{$iPhotoId}">
    <div class="holder">
        <div class="actions">
            {$sActions}
            <a href="#" class="button comment_tr">Comment</a>
        </div>
        <a class="image ajax" href="service.php?id={$iPhotoId}" title="{$sTitle}">
            <img alt="{$sTitle}" src="{$sFolder}{$sFile}">
        </a>
    </div>
    <p class="desc">{$sTitle}</p>
    <p class="info">
        <span class="LikesCount"><strong>{$iLikes}</strong> likes</span>
        <span>{$iRepins} repins</span>
        <span>{$iCmts} comments</span>
    </p>
    <form class="comment" method="post" action="" style="display: none" onsubmit="return submitComment(this, {$iPhotoId})">
        <textarea placeholder="Add a comment..." maxlength="255" name="comment"></textarea>
        <input type="submit" class="button" value="Comment" />
    </form>
</div>
EOL;
        }
        return $sImages;
    }

    // get certain photo info
    function getPhotoInfo($i) {
        $sSQL = "SELECT * FROM `pd_photos` WHERE `id` = '{$i}'";
        $aInfos = $GLOBALS['MySQL']->getAll($sSQL);
        return $aInfos[0];
    }

    // format time by timestamp
    function formatTime($iSec) {
        $sFormat = 'j F Y';
        return gmdate($sFormat, $iSec);
    }

    // insert a new blank photo into DB
    function insertBlankPhoto($sTitle, $iOwner) {
        $sTitle = $GLOBALS['MySQL']->escape($sTitle);
        $iOwner = (int)$iOwner;

        $sSQL = "INSERT INTO `pd_photos` SET `title` = '{$sTitle}', `owner` = '{$iOwner}', `when` = UNIX_TIMESTAMP()";
        $GLOBALS['MySQL']->res($sSQL);
        return $GLOBALS['MySQL']->lastId();
    }

    // update filename
    function updateFilename($i, $sFilename) {
        $sFilename = $GLOBALS['MySQL']->escape($sFilename);

        $sSQL = "UPDATE `pd_photos` SET `filename` = '{$sFilename}' WHERE `id`='{$i}'";
        return $GLOBALS['MySQL']->res($sSQL);
    }

    function acceptLike() {
        $iItemId = (int)$_POST['id']; // prepare necessary information
        $iLoggId = (int)$_SESSION['member_id'];

        if ($iItemId && $iLoggId) {
            // check - if there is any recent record from the same person for last 1 hour
            $iOldId = $GLOBALS['MySQL']->getOne("SELECT `l_item_id` FROM `pd_items_likes` WHERE `l_item_id` = '{$iItemId}' AND `l_pid` = '{$iLoggId}' AND `l_when` >= UNIX_TIMESTAMP() - 3600 LIMIT 1");
            if (! $iOldId) {
                // if everything is fine - we can add a new like
                $GLOBALS['MySQL']->res("INSERT INTO `pd_items_likes` SET `l_item_id` = '{$iItemId}', `l_pid` = '{$iLoggId}', `l_when` = UNIX_TIMESTAMP()");
                // and update total amount of likes
                $GLOBALS['MySQL']->res("UPDATE `pd_photos` SET `like_count` = `like_count` + 1 WHERE `id` = '{$iItemId}'");
            }
            // and return total amount of likes
            return (int)$GLOBALS['MySQL']->getOne("SELECT `like_count` FROM `pd_photos` WHERE `id` = '{$iItemId}'");
        }
    }
    function acceptRepin() {
        $iItemId = (int)$_POST['id']; // prepare necessary information
        $iLoggId = (int)$_SESSION['member_id'];

        if ($iItemId && $iLoggId) {
            $aPhotoInfo = $this->getPhotoInfo($iItemId);

            // check - for already repinned element
            $iOldId = $GLOBALS['MySQL']->getOne("SELECT `id` FROM `pd_photos` WHERE `owner` = '{$iLoggId}' AND `repin_id` = '{$iItemId}'");
            if (! $iOldId) {
                // if everything is fine - add a copy of photo as own photo (repin)
                $sSQL = "INSERT INTO `pd_photos` SET
                            `title` = '{$aPhotoInfo['title']}',
                            `filename` = '{$aPhotoInfo['filename']}',
                            `owner` = '{$iLoggId}',
                            `when` = UNIX_TIMESTAMP(),
                            `repin_id` = '{$iItemId}'
                ";
                $GLOBALS['MySQL']->res($sSQL);

                // update repin count for original photo
                $GLOBALS['MySQL']->res("UPDATE `pd_photos` SET `repin_count` = `repin_count` + 1 WHERE `id` = '{$iItemId}'");
            }
            // and return current member id
            return $iLoggId;
        }
    }

}

$GLOBALS['CPhotos'] = new CPhotos();

You can see, that I modified ‘getAllPhotos’ function. now it can handle with search params, plus, it displays amounts of repins and counts. Since today – repin and like buttons are available only for logged members. You can also find here two new functions ‘acceptLike’ and ‘acceptRepin’. First one is to accept likes, second one is to do ‘repin’. As you see – it just makes a single record to database (a copy of repinned object), but with a link to original photo (repin_id field).

Step 3. Javascript

I updated our main javascript file. There are only two new event handlers:

js/script.js

    // onclick event handler (for like button)
    $('.pin .actions .likebutton').click(function () {
        $(this).attr('disabled', 'disabled');

        var iPinId = $(this).parent().parent().parent().attr('pin_id');
        $.ajax({
          url: 'service.php',
          type: 'POST',
          data: 'add=like&id=' + iPinId,
          cache: false,
          success: function(res){
            $('.pin[pin_id='+iPinId+'] .info .LikesCount strong').text(res);
          }
        });
        return false;
    }); 

    // onclick event handler (for repin button)
    $('.pin .actions .repinbutton').click(function () {
        var iPinId = $(this).parent().parent().parent().attr('pin_id');
        $.ajax({
          url: 'service.php',
          type: 'POST',
          data: 'add=repin&id=' + iPinId,
          cache: false,
          success: function(res){
            window.location.href = 'profile.php?id=' + res;
          }
        });
        return false;
    });

The main idea it to use jQuery ajax to send necessary information about liked or repined photo to our ‘service.php’ server file. Once we click ‘like’ button, we send Photo ID, and then – server returns us total amount of likes for this photo, then we can update ‘like’ counter. The situation is similar for ‘repin’ button. We send photo id to server, once it ‘repins’ selected photo – it relocates us to our profile page (where we can see a result).


Live Demo
download in package

Conclusion

We have just finished our fifth lesson where we are writing our own Pinterest-like script. I hope you enjoy this series. It would be kind of you to share our materials with your friends. Good luck and welcome back!

Enjoyed this Post?

    Tweet
   
   

Stay connected with us:

  • Rss Feed
  • Get Email Updates
  • Follow us on Twitter
  • Follow us on Facebook
  • Follow us on Google+
  • Follow us on LinkedIn
If you enjoyed this article, feel free to share our tutorial with your friends.
Written by: admin on January 10, 2013.

Related Articles

How to create Pinterest-like script – step 6

How to create Pinterest-like script – step 6

How to create Pinterest-like script – step 3

How to create Pinterest-like script – step 3

How to create Pinterest-like script – step 4

How to create Pinterest-like script – step 4

How to create Pinterest-like script – step 2

How to create Pinterest-like script – step 2

21 Comments

    • isska's Gravatar
    • isskaJanuary 11, 2013 12:09 pm

      Thanks so much sir for this tutorials am very happy u created this tutorial since my project is on image, i think i can get some ideals here to work with ;)

    Reply
    • zhang's Gravatar
    • zhangJanuary 20, 2013 2:50 pm

      Hello Andrew,I am a student from China.I pay attention to your site for a long time.I have learned a lot here though I am a green-hand in HTML and CSS.
      ah…My English is so poor,but I still want to show my thanks to you.
      你的这篇教程真是太棒了。在中文里人们把这种网页布局叫做“瀑布流”。
      我想将它应用在我的学校网站上,但是我一点儿也不懂SQL和PHP,我能不能把你的代码完全模仿出来?
      我会经常来这里学习的。在中国,真的很难找到这样专业而且免费的代码教学网站。
      maybe you can understand the sentences above with the help of Google translater.
      Finally,happy new year! Although there are still several days before Chinese traditional new year.

    Reply
      • admin's Gravatar
      • adminFebruary 18, 2013 6:17 am

        Hello Zhang,
        Thank you for your letter, well (I’ve translated your comments in Chinese), yes, you can use our script on your own private website.

      Reply
    • manuel's Gravatar
    • manuelFebruary 22, 2013 4:08 pm

      I love your website and was hoping if there is a way to include facebook login system with it

    Reply
      • admin's Gravatar
      • adminMarch 20, 2013 11:49 am

        Hi Manuel,
        I think that ‘facebook login’ could be done as separated lesson. Actually, you can try to read this article before: http://www.script-tutorials.com/facebook-api-get-friends-list/

      Reply
    • manuels's Gravatar
    • manuelsFebruary 25, 2013 6:10 pm

      thanks for this tutorial
      is there a way to make the script runs profile page with username
      like site.com/profilename

    Reply
      • admin's Gravatar
      • adminMarch 20, 2013 11:50 am

        Yes, sure, if you want to use permalinks, you can add it as a rule for your root .htaccess file.
        in this case, you will need to pass usernames a a GET param (for profile page)

      Reply
    • Kashyap's Gravatar
    • KashyapMarch 7, 2013 2:04 am

      Thank You So much ,,,for givings us ur huge knowledge…..
      i learn many thiung from here infact its amazing web-site…:):):)

    Reply
    • kosh's Gravatar
    • koshMarch 20, 2013 9:17 am

      i’v downloaded the package and installed probably, but i found an issue opening the thumb image !. it keeps loading , could you tell me what i’v to add\edit? thanks

    Reply
      • admin's Gravatar
      • adminMarch 20, 2013 11:55 am

        Hi kosh,
        By default, it displays pre-defined avatar image (images/avatar.jpg). If you’d like to display here custom avatars for your members – you’re welcome to implement this functionality.

      Reply
    • kosh's Gravatar
    • koshMarch 23, 2013 6:23 am

      @admin you didn’t get what i mean.
      in my previous post i asked when i launched this tutorial everything works but whenever i click on an image thumb the original image doesn’t show up, it keep loading but never show up. ! could you help me with it thanks. btw your tutorials are awesome

    Reply
      • admin's Gravatar
      • adminMay 7, 2013 3:41 am

        Hello kosh,
        Ah, I see, then, I think that this would be better to investigate your server response. It should be denied or time outed. Firebug should help you to understand it.

      Reply
    • yemek tarifleri's Gravatar
    • yemek tarifleriMarch 28, 2013 4:08 pm

      Hello,
      Thanks for this material. But we will can see step 6? (follow and url upload). This is will possible?
      Sorry my english not good.

    Reply
      • admin's Gravatar
      • adminMay 7, 2013 3:42 am

        Yes, sure, I have not stopped writing articles about pinterest

      Reply
    • esteban's Gravatar
    • estebanMarch 30, 2013 8:18 pm

      hi,,
      How to submit video ?

      Great work !

    Reply
      • admin's Gravatar
      • adminMay 7, 2013 3:43 am

        Hello Esteban,
        Videos? Hum, this was made especially for photos. If you need a similar solution for videos, so, it is possible too. In this case – you have to start developing it

      Reply
    • Apoorv's Gravatar
    • ApoorvApril 9, 2013 6:22 am

      Hello Admin,
      Can you help me to add infinite scrolling to the code you have given for pinterest.
      I have tried a lot but no code is working.

    Reply
      • admin's Gravatar
      • adminMay 7, 2013 3:44 am

        Hello Apoorv,
        The infinite scroll was added on step 6, you can check it

      Reply
    • Akki's Gravatar
    • AkkiApril 15, 2013 7:08 pm

      I’m also facing the same prob as Kosh, when I click on thumbnail to view full size of image.. it just keeps on loading.. it doesn’t even show any default image… how can I overcome this problem ?? in your demo it is working perfectly..

    Reply
      • admin's Gravatar
      • adminMay 7, 2013 3:46 am

        Hi Akki,
        I am curious why it so, it shouldn’t be so. Try to investigate a server response (in firebug). Maybe your server refuses ajax connections, or it generates an error in response.

      Reply
    • Akki's Gravatar
    • AkkiApril 17, 2013 2:08 pm

      Great tutorial I must say, it would be more good if you add ” Create Board and add pin to the board” similar as Board in Pinterest.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

*

*

CAPTCHA Image
Refresh Image

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Popular Tutorials

  • Pure HTML5 file upload
  • CSS3 Modal Popups
  • How to Easily Make a PHP Chat Application
  • How to create easy pagination with jQuery
  • Form Validation with Javascript and PHP
  • CSS3 Responsive menu
  • Pure CSS3 LavaLamp Menu
  • Functional Programming – How to Write Functional Code in PHP

Tags

3d AJAX animated animation app applications apps canvas captcha chat system coding creating css css3 developers dropdown effect flash forms fresh gallery game development how-to html html5 html5 games image Infographic iphone javascript jQuery layout menu navigation offer photo photo gallery PHP plugin plugins roundup tutorial tutorials website xslt

Recent Tutorials

  • Pane for drawing in pseudo 3D
  • Functional Programming – How to Write Functional Code in PHP
  • PHP Debugging and Profiling – Xdebug
  • Responsive Photo Gallery with LazyLoad (least.js)
  • Permalinks tutorial
  • How to create Pinterest-like script – step 6
  • WYSIWYG and WYSIWYM Editors
  • Neat and modern design – responsive
  • Facebook
  • Twitter
  • G+

Who is behind Script Tutorials

author

Hello there! My name is Andrew and I have been doing web development for years. Frankly, not only web-development, and system-development too. This site is the place where I get to teach and share my experience for the web.

Read more

Contact Us

Contact Us

  • Advertise
  • Contact Us
  • About
  • License

Copyright © 2009-2012 Script tutorials