We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 18397
    • 3,250 Posts
    I plan on releasing Ditto 2.0.1, the first episode of the Ditto screen cast, and an updated version of DittoCal on Sunday. Please download a dev copy of Ditto from http://www.modxcms.com/ditto_download.html and put it through its paces. I’ll post a dev copy to the public a little later (its 3am now... I must sleep!). You can get a sneak peek of the screencast at http://ditto.modxcms.com/screencast/episode_001.mov. I’ve attached a copy of the DittoCal snippet code (for use with Ditto 2.0.1) to the end of this post (the JSON class is the same).

    As usual please keep the previews internal. Thanks.

    <?php
    
    /* -------------------------------------------------------------
    :: Snippet: DittoCal
    ----------------------------------------------------------------
        Short Description:
            Calendar to display blog post navigation.
    
        Version:
            1.2
    
        Created by:
    	    Kyle Jaebker (kylej - [email protected])
    
    	Modified by:
    		Mark Kaplan (modxcms.com)
    		
        Date:
            18-Mar-07
    
        Required Usage:
            [!DittoCal?calSource=``!]
    
            You must create a new document with the following settings:
                template: blank
                show in menu: no
                published: yes
                searchable: no
                content type: text/plain
                document content:
                [!Ditto? &parents=`yourblogfolder` &display=`all` &format=`json`!]
    
            This document is used to output your post data so that it
            can be read into the calendar.  You should set the startId
            to your blog folder and set summarize to the max number
            of posts you expect to have.  Leave everything else the same
            as above.
    
        Changelog:
    		18-MAR-07 - Made compatible with Ditto 2.0.1. Added &id and &landing for use
    		with Ditto. If you have a Ditto call on the document with the same id as
    		&landing and ID as &id with &extenders=`dateFilter`, DittoCal will pass 
    		the required information to filter the results to only show documents on
    		that day.
            17-JUL-06 - Added code to remove next link if next month is past the most
            recent post.  If day is clicked on calendar the calendar will remain on
            that month when new page is loaded.  A new class will be assigned to the
            day that was selected as well.  Added placeholder output support and debug
            output.
    
    ----------------------------------------------------------------
    :: Description
    ----------------------------------------------------------------
        DittoCal creates a small monthly calendar to display links
        to your blog posts.  The initial display shows the month
        of your latest blog post.
    
    ----------------------------------------------------------------
    :: Parameters
    ----------------------------------------------------------------
    
        calSource - the path to the document created above
            (i.e. http://www.muddydogpaws.com/blog_json)
        linkClass - class for date links
        dayNameLength - how many characters of the day to display (default: 3)
        firstDay - first day of the week (default: 0)
            values: 0 - sunday
                    1 - monday
                    2 - tuesday
                    3 - wednesday
                    4 - thursday
                    5 - friday
                    6 - saturday
        showPn - show the previous/next links [1 | 0] (default: 1)
        debug - set to 1 for debug output [1 | 0] (default: 0)
        ph - name of placeholder to output to
        activeDay - class for the day clicked in calendar
    	id - Ditto ID
    	landing - document id of the document containing a Ditto call with &id=`id` and &extenders=`dateFilter`
    
    ----------------------------------------------------------------
    :: Example Call
    ----------------------------------------------------------------
    
    [!DittoCal? &calSource=`http://www.muddydogpaws.com/blog_json` &dayNameLength=`1`!]
    
    ----------------------------------------------------------------
    :: Credits
    ----------------------------------------------------------------
    
        The code to generate the calendar was provided by:
    
        PHP Calendar (version 2.3), written by Keith Devens
        http://keithdevens.com/software/php_calendar
        see example at http://keithdevens.com/weblog
        License: http://keithdevens.com/software/license
    
    ------------------------------------------------------------- */
    $prefix = isset($id) ? $id : "cal";
    $landing = isset($landing) ? $landing : 0;
    $calSource = isset($calSource) ? $calSource : 0;
    $linkClass = isset($linkClass) ? $linkClass : 'cal_link';
    $dayNameLength = isset($dayNameLength) ? $dayNameLength : 3;
    $firstDay = isset($firstDay) ? $firstDay : 0;
    $showPn = isset($showPn) ? $showPn : 1;
    $debug = isset($debug) ? $debug : 0;
    $ph = isset($ph) ? $ph : 0;
    $activeDay = isset($activeDay) ? $activeDay : 'curDay';
    
    $snippetPath = $modx->config['base_path'] . 'assets/snippets/';
    require_once($snippetPath.'DittoCal/JSON.php');
    
    //Set this array if you want a link for the month
    /*
    $monthLinks = array(
        '2006' => array(
            '03'=>'http://www.muddydogpaws.com/json_test',
            '04'=>'http://www.muddydogpaws.com/notebook')
    );
    */
    
    if (!$calSource) {
        return 'You must specify a source for your calendar.';
    }
    
    //Get the json formatted data
    $source = file_get_contents($calSource);
    
    if ($debug) {
        $debugOutput .= '<h2>DittoCal Debug Output</h2>';
        $debugOutput .= '<h3>Initial Data from Json</h3>';
        $debugOutput .= '<pre>' . print_r($source,TRUE) . '</pre>';
    }
    
    // create a new instance of Services_JSON
    if (class_exists(Services_JSON)) {
        $json = new Services_JSON();
    } else {
        return 'The class Services_JSON could not be found.  Make sure you have the file JSON.php in the directory assets/snippets/DittoCal';
    }
    
    $postData = $json->decode($source);
    
    if ($debug) {
        $debugOutput .= '<h3>Data after JSON decoding</h3>';
        $debugOutput .= '<pre>' . print_r($postData,TRUE) . '</pre>';
    }
    
    //Use the month & year passed-in if set else use first post as month & year
    if (isset($_GET['cal_month']) && isset($_GET['cal_year'])) {
        $filterMonth = $_GET['cal_month'];
        $filterYear = $_GET['cal_year'];
    } else {
    	$timestamp = getDate($postData->entries[0]->date);
        $filterMonth = $timestamp["mon"];
        $filterYear = $timestamp["year"];
    }
    
    if ($debug) {
        $debugOutput .= '<h3>Filter Settings</h3>';
        $debugOutput .= '<p>Filter Month: ' . $filterMonth . '<br/>Filter Year: ' . $filterYear . '</p>';
    }
    
    $cal_days = array();
    
    //Filter out posts that are not in the specified month & year, set the link
    if (is_array($postData->entries)) {
        foreach($postData->entries as $n => $v) {
    		$vTimestamp = getDate($v->date);
    	    $checkMonth = $vTimestamp["mon"];
    	    $checkYear = $vTimestamp["year"];
            if (($checkMonth != $filterMonth) || ($checkYear != $filterYear)) {
                unset($postData->entries[$n]);
            } else {
                $theDay = $vTimestamp["mday"];
    			$url = ($landing === 0) ? $v->link : $modx->makeURL($landing);
                if($modx->config['friendly_urls']) {
                    $dayUrl = $url . '?'.$prefix.'_month=' . $checkMonth . '&'.$prefix.'_year=' . $checkYear . '&'.$prefix.'_day=' . $theDay;
                } else {
                    $dayUrl = $url . '&'.$prefix.'_month=' . $checkMonth . '&'.$prefix.'_year=' . $checkYear . '&'.$prefix.'_day=' . $theDay;
                }
    
                if(isset($_GET[$prefix.'_day']) && $_GET[$prefix.'_day'] == $theDay) {
                    $dayClass = $activeDay;
                } else {
                    $dayClass = $linkClass;
                }
    
                $cal_days[$theDay] = array($dayUrl,$dayClass,$v->title);
            }
        }
    } else {
        if (!isset($debugOutput)) $debugOutput = '';
        $debugOutput .= '<h3>Processing Error</h3><p>There was an error processing the json data. Set the debug param equal to 1 for more info.</p>';
        return $debugOutput;
    }
    
    //Sort the posts by day
    ksort($cal_days);
    
    if ($debug) {
        $debugOutput .= '<h3>Day Array for output</h3>';
        $debugOutput .= '<pre>' . print_r($cal_days,TRUE) . '</pre>';
        if (isset($monthLinks)) {
            $debugOutput .= '<h3>Month Links Array</h3><pre>' . print_r($monthLinks,TRUE) . '</pre>';
        }
    }
    
    //Set the prev & next Links
    if ($showPn) {
        $numMonth = intval($filterMonth);
        $numYear = intval($filterYear);
    
        if ($numMonth == 1) {
            $prevMonth = 12;
            $prevYear = $numYear - 1;
            $nextYear = $numYear;
            $nextMonth = $numMonth + 1;
        } elseif ($numMonth == 12) {
            $prevMonth = $numMonth - 1;
            $prevYear = $numYear;
            $nextYear = $numYear + 1;
            $nextMonth = 1;
        } else {
            $prevMonth = $numMonth - 1;
            $prevYear = $numYear;
            $nextYear = $numYear;
            $nextMonth = $numMonth + 1;
        }
    
        $nextMonth = $nextMonth < 10 ? '0' . $nextMonth : $nextMonth;
        $prevMonth = $prevMonth < 10 ? '0' . $prevMonth : $prevMonth;
    
        $prevArgs = 'cal_month=' . $prevMonth . '&cal_year=' . $prevYear;
        $nextArgs = 'cal_month=' . $nextMonth . '&cal_year=' . $nextYear;
    
        $prevLink = $modx->makeUrl($modx->documentObject['id'],'',$prevArgs);
        $nextLink = $modx->makeUrl($modx->documentObject['id'],'',$nextArgs);
    
        $checkCurMonth = date('n',time());
        $checkCurYear = date('Y',time());
    
        if ($checkCurMonth == $numMonth && $checkCurYear == $numYear) {
            $pn = array('«'=>$prevLink);
        } else {
            $pn = array('«'=>$prevLink,'»'=>$nextLink);
        }
    } else {
        $pn = array();
    }
    
    //Set month link if specified
    if (isset($monthLinks[$filterYear][$filterMonth])) {
        $monthLink = $monthLinks[$filterYear][$filterMonth];
    } else {
        $monthLink = NULL;
    }
    
    $output = generate_calendar($filterYear,$filterMonth,$cal_days,$dayNameLength,$monthLink,$firstDay,$pn);
    
    //Output the calendar
    if ($debug) {
        $output = $output . $debugOutput;
    }
    
    if ($ph) {
        $modx->setPlaceholder($ph,$output);
    } else {
        return $output;
    }
    
    # PHP Calendar (version 2.3), written by Keith Devens
    # http://keithdevens.com/software/php_calendar
    #  see example at http://keithdevens.com/weblog
    # License: http://keithdevens.com/software/license
    
    function generate_calendar($year, $month, $days = array(), $day_name_length = 3, $month_href = NULL, $first_day = 0, $pn = array()){
    	$first_of_month = gmmktime(0,0,0,$month,1,$year);
    	#remember that mktime will automatically correct if invalid dates are entered
    	# for instance, mktime(0,0,0,12,32,1997) will be the date for Jan 1, 1998
    	# this provides a built in "rounding" feature to generate_calendar()
    
    	$day_names = array(); #generate all the day names according to the current locale
    	for($n=0,$t=(3+$first_day)*86400; $n<7; $n++,$t+=86400) #January 4, 1970 was a Sunday
    		$day_names[$n] = ucfirst(gmstrftime('%A',$t)); #%A means full textual day name
    
    	list($month, $year, $month_name, $weekday) = explode(',',gmstrftime('%m,%Y,%B,%w',$first_of_month));
    	$weekday = ($weekday + 7 - $first_day) % 7; #adjust for $first_day
    	$title   = htmlentities(ucfirst($month_name)).' '.$year;  #note that some locales don't capitalize month and day names
    
    	#Begin calendar. Uses a real <caption>. See http://diveintomark.org/archives/2002/07/03
    	@list($p, $pl) = each($pn); @list($n, $nl) = each($pn); #previous and next links, if applicable
    	if($p) $p = '<span class="calendar-prev">'.($pl ? '<a href="'.htmlspecialchars($pl).'" id="calendar-prev">'.$p.'</a>' : $p).'</span> ';
    	if($n) $n = ' <span class="calendar-next">'.($nl ? '<a href="'.htmlspecialchars($nl).'" id="calendar-next">'.$n.'</a>' : $n).'</span>';
    	$calendar = '<table class="calendar" cellspacing="0" cellpadding="0">'."\n".
    		'<caption class="calendar-month">'.$p.($month_href ? '<a href="'.htmlspecialchars($month_href).'">'.$title.'</a>' : $title).$n."</caption>\n<tr>";
    
    	if($day_name_length){ #if the day names should be shown ($day_name_length > 0)
    		#if day_name_length is >3, the full name of the day will be printed
    		foreach($day_names as $d)
    			$calendar .= '<th abbr="'.htmlentities($d).'">'.htmlentities($day_name_length < 4 ? substr($d,0,$day_name_length) : $d).'</th>';
    		$calendar .= "</tr>\n<tr>";
    	}
    
    	if($weekday > 0) $calendar .= '<td colspan="'.$weekday.'"> </td>'; #initial 'empty' days
    	for($day=1,$days_in_month=gmdate('t',$first_of_month); $day<=$days_in_month; $day++,$weekday++){
    		if($weekday == 7){
    			$weekday   = 0; #start a new week
    			$calendar .= "</tr>\n<tr>";
    		}
    		if(isset($days[$day]) and is_array($days[$day])){
    			@list($link, $classes, $title, $content) = $days[$day];
    			if(is_null($content))  $content  = $day;
    			$calendar .= '<td'.($classes ? ' class="'.htmlspecialchars($classes).'">' : '>').
    				($link ? '<a href="'.htmlspecialchars($link).'" title="'.htmlspecialchars($title).'">'.$content.'</a>' : $content).'</td>';
    		}
    		else $calendar .= "<td>$day</td>";
    	}
    	if($weekday != 7) $calendar .= '<td colspan="'.(7-$weekday).'"> </td>'; #remaining "empty" days
    
    	return $calendar."</tr>\n</table>\n";
    }
    
    
    ?>
    
      • 33337
      • 3,975 Posts
      *applause*

      Great work Mark! laugh
        Zaigham R - MODX Professional | Skype | Email | Twitter

        Digging the interwebs for #MODX gems and bringing it to you. modx.link
        • 10487 MODX Staff
        • 1,535 Posts
        Great screencast grin I was wondering how to do tagging the other day ... and I now I know!
          Garry Nutting
          Senior Developer
          MODX, LLC

          Email: [email protected]
          Twitter: @garryn
          Web: modx.com
          • 23491 ☆ A M B ☆
          • 1,056 Posts
          Awesome stuff, Mark. This type of screencasting will be very beneficial to the members. Great work!
            Mike Reid - www.pixelchutes.com
            MODx Ambassador / Contributor
            [Module] MultiMedia Manager / [Module] SiteSearch / [Snippet] DocPassword / [Plugin] EditArea / We support FoxyCart
            ________________________________
            Where every pixel matters.
            • 6726
            • 7,075 Posts
            Ditto !

            I do believe in the virtue of screencasting and doing some myself for clients (and for the future french MODx website), but this one is examplary of how to communicate things fast and easy : great job !

              .: COO - Commerce Guys - Community Driven Innovation :.


              MODx est l&#39;outil id
              • 36541
              • 222 Posts
              Quote from: pixelchutes at Mar 19, 2007, 12:04 PM

              Awesome stuff, Mark. This type of screencasting will be very beneficial to the members. Great work!

              Ditto that!

              I’ve got just one suggestion - to use a more descriptive name for the file to let it identify itself. `episode_001.mov` doesn’t tell anything in my file listing smiley
                This is the web: the only thing you know about who will come is that you don't know who will come.
                • 18397
                • 3,250 Posts
                They are named like that so I can create an automatic RSS feed for them in the future.
                  • 36541
                  • 222 Posts
                  I thought about somethin like `modx-ditto-screencast-episode-001.mov`. Still, it’s just my 2 c.
                    This is the web: the only thing you know about who will come is that you don't know who will come.