How to create Pinterest-like script – step 2

Tutorials

Today I would like to introduce our second turorial where we are creating own Pinterest-like script. For today I prepared next interesting features: html5 photo uploader (please pay attention, that this feature works well in all modern browsers except for the IE) and ajaxy popup to display full-size photos. I used free jQuery plugin ColorBox to do it. Well, I think that now we have to test it and understand the codes.

Now you can check our demonstration and download the sources:

Live Demo

[sociallocker]

download in package

[/sociallocker]


Step 1. HTML

As usual, our first step is html markup. I made one important thing – I moved whole file into ‘templates’ folder. And, made few changes in it: added style and script files for ColorBox, upload form was changed slightly, and finally, I replaced hardcoded pins to template key. It is called {images_set}. Now, our index.html template looks like that:

templates/index.html

01 <!DOCTYPE html>
02 <html lang="en" >
03     <head>
04         <meta charset="utf-8" />
05         <meta name="author" content="Script Tutorials" />
06         <title>How to create Pinterest-like script - step 2 | Script Tutorials</title>
07         <!-- add styles -->
08         <link href="css/main.css" rel="stylesheet" type="text/css" />
09         <link href="css/colorbox.css" rel="stylesheet" type="text/css" />
10         <!-- add scripts -->
11         <script src="js/jquery.min.js"></script>
12         <script src="js/jquery.colorbox-min.js"></script>
13         <script src="js/jquery.masonry.min.js"></script>
14         <script src="js/script.js"></script>
15     </head>
16     <body>
17         <!-- header panel -->
18         <div class="header_panel">
19             <!-- logo -->
20             <a href="#" class="logo"></a>
21             <!-- search form -->
22             <form action="" method="get" class="search">
23                 <input autocomplete="off" name="q" size="27" placeholder="Search" type="text" />
24                 <input name="search" type="submit" />
25             </form>
26             <!-- navigation menu -->
27             <ul class="nav">
28                 <li><a href="#add_form" id="login_pop">Add +</a></li>
29                 <li>
30                     <a href="#">About<span></span></a>
31                     <ul>
32                         <li><a href="#">Help</a></li>
33                         <li><a href="#">Pin It Button</a></li>
34                         <li><a href="#" target="_blank">For Businesses</a></li>
35                         <li class="div"><a href="#">Careers</a></li>
36                         <li><a href="#">Team</a></li>
37                         <li><a href="#">Blog</a></li>
38                         <li class="div"><a href="#">Terms of Service</a></li>
39                         <li><a href="#">Privacy Policy</a></li>
40                         <li><a href="#">Copyright</a></li>
41                         <li><a href="#">Trademark</a></li>
42                     </ul>
43                 </li>
44                 <li>
45                     <a href="#">Profile<span></span></a>
46                     <ul>
47                         <li><a href="#">Invite Friends</a></li>
48                         <li><a href="#">Find Friends</a></li>
49                         <li class="div"><a href="#">Boards</a></li>
50                         <li><a href="#">Pins</a></li>
51                         <li><a href="#">Likes</a></li>
52                         <li class="div"><a href="#">Settings</a></li>
53                         <li><a href="#">Logout</a></li>
54                     </ul>
55                 </li>
56                 <li>
57                     <a href="https://www.script-tutorials.com/pinterest-like-script-step-2/">Back to tutorial<span></span></a>
58                 </li>
59             </ul>
60         </div>
61         <!-- upload form -->
62         <a href="#x" class="overlay" id="add_form"></a>
63         <div class="popup">
64             <div class="header">
65                 <a class="close" href="#close">x</a>
66                 <h2>Upload a Pin</h2>
67             </div>
68             <form id="upload_form">
69                 <input type="file" name="image_file" id="image_file" onchange="" />
70             </form>
71             <div id="upload_result"></div>
72         </div>
73         <!-- main container -->
74         <div class="main_container">
75             {images_set}
76         </div>
77     </body>
78 </html>

Step 2. PHP

Now, our main index file is index.php. Mainly because we have to prepare list of images (HTML) at this step. Please review this file:

index.php

01 // set warning level
02 if (version_compare(phpversion(), '5.3.0''>=')  == 1)
03   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
04 else
05   error_reporting(E_ALL & ~E_NOTICE);
06 $sFolder 'photos/';
07 $aAllowedExt array('jpg' => 1, 'png' => 1);
08 $sImages '';
09 $iCnt = 1;
10 $rDir = opendir($sFolder);
11 if ($rDir) {
12     while ($sFile = readdir($rDir)) {
13         if ($sFile == '.' || $sFile == '..' || ! is_file($sFolder $sFile))
14             continue;
15         $aPathInfo pathinfo($sFile);
16         $sExt strtolower($aPathInfo['extension']);
17         if (isset($aAllowedExt[$sExt])) {
18             if (strpos($sFile'_full') === false) {
19                 $sFilename $aPathInfo['filename'];
20                 $sImages .= <<<EOL
21 <!-- pin element {$iCnt} -->
22 <div class="pin">
23     <div class="holder">
24         <div class="actions" pin_id="{$iCnt}">
25             <a href="#" class="button">Repin</a>
26             <a href="#" class="button">Like</a>
27             <a href="#" class="button comment_tr">Comment</a>
28         </div>
29         <a class="image ajax" href="service.php?id={$sFilename}&ext={$sExt}" title="Photo number {$iCnt}">
30             <img alt="Photo number {$iCnt}" src="{$sFolder}{$sFile}">
31         </a>
32     </div>
33     <p class="desc">Photo number {$iCnt} description</p>
34     <p class="info">
35         <span>{$iCnt} likes</span>
36         <span>{$iCnt} repins</span>
37     </p>
38     <form class="comment" method="post" action="" style="display: none">
39         <input type="hidden" name="id" value="0" />
40         <textarea placeholder="Add a comment..." maxlength="1000"></textarea>
41         <button type="button" class="button">Comment</button>
42     </form>
43 </div>
44 EOL;
45                 $iCnt++;
46             }
47         }
48     }
49     closedir$rDir );
50 }
51 // draw common page
52 $aKeys array(
53     '{images_set}' => $sImages
54 );
55 echo strtr(file_get_contents('templates/index.html'), $aKeys);

Everything is easy: basically, we parse all image files in ‘photos’ folder, and prepare our pins (image objects) to display at index page. For today’s lesson, we don’t use database, but we will (in next lesson). Because we still have to link comments and authors with certain images. Please pay attention how we use ColorBox plugin: we just can set class name as ‘ajax’, and add necessary url (href) to a page with ajax response (bigger image), we use ‘service.php’ to generate it. Let’s review this file:

service.php

01 // set warning level
02 if (version_compare(phpversion(), '5.3.0''>=')  == 1)
03   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
04 else
05   error_reporting(E_ALL & ~E_NOTICE);
06 $i stripslashes(strip_tags($_GET['id']));
07 $ext stripslashes(strip_tags($_GET['ext']));
08 // if something is wrong
09 if (! $i || ! $ext) {
10     exit;
11 }
12 // prepare full image path
13 $sFullImgPath $sFilename '';
14 $sFolder 'photos/';
15 $aAllowedExt array('jpg' => 1, 'png' => 1);
16 $aPathInfo pathinfo($i '.' $ext);
17 $sExt strtolower($aPathInfo['extension']);
18 if (isset($aAllowedExt[$sExt])) {
19     $sFilename =  $aPathInfo['filename'];
20     $sFullImgPath $sFolder $sFilename '_full.' $sExt;
21 }
22 if (! $sFullImgPath) {
23     exit;
24 }
25 ?>
26 <div class="pin bigpin">
27     <div class="owner">
28         <a href="#" class="button follow_button">Follow</a>
29         <a target="_blank" class="owner_img" href="#">
30             <img alt="Mr Brown" src="images/avatar.jpg" />
31         </a>
32         <p class="owner_name"><a target="_blank" href="#">Mr Brown</a></p>
33         <p class="owner_when">Uploaded X months ago</p>
34     </div>
35     <div class="holder">
36         <div class="actions">
37             <a href="#" class="button">Repin</a>
38             <a href="#" class="button">Like</a>
39         </div>
40         <a class="image" href="#" title="Photo <?= $sFilename ?>">
41             <img alt="Photo <?= $sFilename ?>" src="<?= $sFullImgPath ?>">
42         </a>
43     </div>
44     <p class="desc">Photo <?= $sFilename ?> description</p>
45     <div class="comments"></div>
46     <form class="comment" method="post" action="#">
47         <input type="hidden" name="id" value="0" />
48         <textarea placeholder="Add a comment..." maxlength="1000"></textarea>
49         <button type="button" class="button">Comment</button>
50     </form>
51 </div>

As you see, right now we use this file only to generate bigger block with image (and – with several other elements). I’m going to use this file to work with comments, likes, and possible something else. Finally, as I mentioned – I added the ability to upload files (images). Here is it:

upload.php

01 // set warning level
02 if (version_compare(phpversion(), '5.3.0''>=')  == 1)
03   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
04 else
05   error_reporting(E_ALL & ~E_NOTICE);
06 function uploadImageFile() { // Note: GD library is required for this upload function
07     $iDefWidth = 192; // default photos width (in case of resize)
08     $iFDefWidth = 556; // full default photos width (in case of resize)
09     if ($_SERVER['REQUEST_METHOD'] == 'POST') {
10         $iWidth $iHeight $iFDefWidth// desired image dimensions
11         $iJpgQuality = 75;
12         if ($_FILES) {
13             // if there are no errors and filesize less than 400kb
14             if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 400 * 1024) {
15                 if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {
16                     // new unique filename
17                     $sTempFileName 'photos/' . md5(time().rand());
18                     // move uploaded file into cache folder
19                     move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName);
20                     // change file permission to 644
21                     @chmod($sTempFileName, 0644);
22                     // if temp file exists
23                     if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
24                         $aSize getimagesize($sTempFileName); // obtain image info
25                         if (!$aSize) {
26                             @unlink($sTempFileName);
27                             return;
28                         }
29                         // check for image type and create a new image from file
30                         switch($aSize[2]) {
31                             case IMAGETYPE_JPEG:
32                                 $sExt '.jpg';
33                                 $vImg = @imagecreatefromjpeg($sTempFileName);
34                                 break;
35                             case IMAGETYPE_PNG:
36                                 $sExt '.png';
37                                 $vImg = @imagecreatefrompng($sTempFileName);
38                                 break;
39                             default:
40                                 @unlink($sTempFileName);
41                                 return;
42                         }
43                         // get source image width and height
44                         $iSrcWidth = imagesx($vImg);
45                         $iSrcHeight = imagesy($vImg);
46                         // recalculate height (depends on width)
47                         $iHeight $iSrcHeight $iWidth $iSrcWidth;
48                         // create a new true color image
49                         $vDstImg = @imagecreatetruecolor( $iWidth$iHeight );
50                         // copy and resize
51                         imagecopyresampled($vDstImg$vImg, 0, 0, 0, 0, $iWidth$iHeight$iSrcWidth$iSrcHeight);
52                         // define a result image filename
53                         $sResultFileName $sTempFileName '_full' $sExt;
54                         // output image to file and set permission 644
55                         imagejpeg($vDstImg$sResultFileName$iJpgQuality);
56                         @chmod($sResultFileName, 0644);
57                         // and, prepare a thumbnail as well
58                         $iWidth $iDefWidth;
59                         $iHeight $iSrcHeight $iWidth $iSrcWidth;
60                         $vDstThImg = @imagecreatetruecolor($iWidth$iHeight);
61                         imagecopyresampled($vDstThImg$vImg, 0, 0, 0, 0, $iWidth$iHeight$iSrcWidth$iSrcHeight);
62                         $sResultThumnName $sTempFileName $sExt;
63                         imagejpeg($vDstThImg$sResultThumnName$iJpgQuality);
64                         @chmod($sResultThumnName, 0644);
65                         // unlink temp file
66                         @unlink($sTempFileName);
67                         return $sResultFileName;
68                     }
69                 }
70             }
71         }
72     }
73 }
74 $sImage = uploadImageFile();
75 echo '1';

Our script accepts only 2 formats: png and jpg images. It uses GD library to resize incoming image into 2 dimensions (with width = 192px as a thumbnail and 556px as a full image).

Step 3. CSS

Now, I should give you all the styles for our bigger unit (which we get when we click at pin object):

css/main.css

01 /* big pin styles */
02 .bigpin {
03     background-colortransparent;
04     box-shadow: none;
05     floatnone;
06     margin0;
07     padding5px;
08     width600px;
09 }
10 .bigpin .owner {
11     border-bottom1px solid #D1CDCD;
12     overflowhidden;
13     padding-bottom10px;
14 }
15 .bigpin .follow_button {
16     background-color#D43638;
17     background-image: -webkit-linear-gradient(center top #EB5367#E04751 50%#DE404A 50%#D43638);
18     background-image: -moz-linear-gradient(center top #EB5367#E04751 50%#DE404A 50%#D43638);
19     background-image: linear-gradient(center top #EB5367#E04751 50%#DE404A 50%#D43638);
20     border-color#910101;
21     color#FCF9F9;
22     font-size13px;
23     padding7px 9px;
24     text-shadow0 -1px rgba(3425250.5);
25 }
26 .bigpin .owner_img {
27     floatleft;
28     margin-right9px;
29     width50px;
30 }
31 .bigpin .owner_img img {
32     displayblock;
33     height50px;
34     width50px;
35 }
36 .bigpin .owner_name {
37     font-size23px;
38     line-height1em;
39     margin-bottom2px;
40 }
41 .bigpin .owner_when {
42     color#8C7E7E;
43     displayblock;
44     font-size13px;
45     margin5px 0 0;
46     padding-left60px;
47 }
48 .bigpin .holder {
49     margin-top10px;
50 }
51 .bigpin .actions {
52     left7px;
53     top15px;
54 }
55 .bigpin .image {
56     cursorpointer;
57 }
58 .bigpin .image img {
59     displayblock;
60     margin0 auto;
61     max-widthnone;
62 }
63 .bigpin .desc {
64     border-bottom1px solid #D1CDCD;
65     padding-bottom10px;
66 }
67 .bigpin .comments {
68     margin20px 0;
69     overflowhidden;
70     width99%;
71 }
72 .bigpin .comments p {
73     color#211922;
74     font-size13px;
75     line-height1.33em;
76     margin-bottom10px;
77     word-wrap: break-word;
78 }
79 .bigpin .comment {
80     background-colortransparent;
81     border-topmedium none;
82     box-shadow: none;
83     margin0;
84     padding0;
85 }
86 .bigpin  .comment textarea {
87     padding10px;
88     margin-bottom10px;
89     width96%;
90 }

Step 4. JS

As the latests step for today – updated javascript code:

js/script.js

01 function fileSelectHandler() {
02     // get selected file
03     var oFile = $('#image_file')[0].files[0];
04     // html5 file upload
05     var formData = new FormData($('#upload_form')[0]);
06     $.ajax({
07         url: 'upload.php'//server script to process data
08         type: 'POST',
09         // ajax events
10         beforeSend: function() {
11         },
12         success: function(e) {
13             $('#upload_result').html('Thank you for your photo').show();
14             setTimeout(function() {
15                 $("#upload_result").hide().empty();
16             }, 4000);
17         },
18         error: function(e) {
19             $('#upload_result').html('Error while processing uploaded image');
20         },
21         // form data
22         data: formData,
23         // options to tell JQuery not to process data or worry about content-type
24         cache: false,
25         contentType: false,
26         processData: false
27     });
28 }
29 $(document).ready(function(){
30     // file field change handler
31     $('#image_file').change(function(){
32         var file = this.files[0];
33         name = file.name;
34         size = file.size;
35         type = file.type;
36         // extra validation
37         if (name && size)  {
38             if (! file.type.match('image.*')) {
39                 alert("Select image please");
40             else {
41                 fileSelectHandler();
42             }
43         }
44     });
45     // masonry initialization
46     $('.main_container').masonry({
47         // options
48         itemSelector : '.pin',
49         isAnimated: true,
50         isFitWidth: true
51     });
52     // onclick event handler (for comments)
53     $('.comment_tr').click(function () {
54         $(this).toggleClass('disabled');
55         $(this).parent().parent().parent().find('form').slideToggle(250, function () {
56             $('.main_container').masonry();
57         });
58     });
59     $('.ajax').colorbox({
60         onOpen:function(){
61         },
62         onLoad:function(){
63         },
64         onComplete:function(){
65             $(this).colorbox.resize();
66         },
67         onCleanup:function(){
68         },
69         onClosed:function(){
70         }
71     });
72 });

A new function was added: fileSelectHandler. It uses html5 to POST image file to server. Once it has received a file, it returns us a message if our image was accepted or not. Also, I added here ‘colorbox’ initialization. It is very easy to use this plugin.


Live Demo

Conclusion

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

Rate article