Good morning,
I am trying to alter the output of a calendar WordPress plugin for a website. I need to be able to group items by month. Ideally, I would have the month and year and below that would be a list of all the objects from that month. I have everything good to go except for the grouping by month and year.
The table is structured like this:
id | event_start | event_end | event_title | event_desc
2 | 1309935600 | 309939200 | test | Donec iaculis...
I'm new to PHP and MySQL but here's the code that is currently using (I did not write this, I've modified it for my own use -- most html / css removed):
// Add the shortcode for displaying the event on pages
function displayevents( $atts ) {
global $wpdb;
setlocale(LC_ALL, get_locale());
$table_name = $wpdb->prefix . "simple_events";
// VARIATIONS: EXPIRED / ALL / UPCOMING
if($atts['age']) {
$age = $atts['age'];
if($age == "expired") {
$range = "event_end <= " . time();
} elseif($age == "all") {
$range = "event_end > 946706400"; // timestamp for jan 1st 2000 - assuming no event will be creted before that date
} else {
$range = "event end > " . time();
}
}
if($atts['label']) $label = strtolower($atts['label']);
if($atts['limit'] > 0) { $limit = "LIMIT 0, " . $atts['limit']; } else { $limit = ""; }
if( $age && $label ) {
$allevents = $wpdb->get_results(" SELECT * FROM $table_name WHERE event_label = '$label' AND $range ORDER BY event_start $limit", "ARRAY_A");
} elseif($age) {
$allevents = $wpdb->get_results(" SELECT * FROM $table_name WHERE $range ORDER BY event_start $limit", "ARRAY_A");
} elseif($label) {
$currentTime = time();
$allevents = $wpdb->get_results(" SELECT * FROM $table_name WHERE event_label = '$label' AND event_end >= $currentTime ORDER BY event_start $limit", "ARRAY_A");
} else {
$currentTime = time();
$allevents = $wpdb->get_results(" SELECT * FROM $table_name WHERE event_end >= $currentTime ORDER BY event_start $limit", "ARRAY_A");
}
foreach ($allevents as $event) {
// decide if the year needs to be mentioned
if(date('Y',$event['event_start']) == date('Y',time())) {
$eventtime = strftime( __('%l:%M',SE_TEXTDOMAIN),$event['event_start']);
} else {
$eventtime = strftime( __('%l:%M',SE_TEXTDOMAIN),$event['event_start']);
}
$the_events[] =
strftime( __('%d',SE_TEXTDOMAIN),$event['event_end']).
stripslashes($event['event_title']).
stripslashes($event['event_desc']).
$eventtime.
' to '.
strftime( __('%l:%M',SE_TEXTDOMAIN),$event['event_end']).
$evt_loc.
$evt_url;
} // end foreach ($allevents as $event)
$items = implode($the_events);
return($items);
}
Any help would be greatly appreciated. The current output can be seen here: http://nwtechanddesign.com/jariccodance/calendar/
The desired output (styling apart) can be seen here: http://nwtechanddesign.com/wp-content/blogs.dir/11/calendar.jpg
TIA
I'm not 100% sure what you're doing with that string that you're getting back out, so I can't really
answer in a way that you'll just be able to drop in, but, given that you're creating some big string
from imploding arrays, I guess you just want to know how to drop a header in, at the right places.
Assuming your array is sorted right, which based on the queries, it looks like it should be coming
out in order, you could do something like:
$curMonth = "";
$curYear = "";
foreach($allEvents as $event)
{
// If we encounter a new month or year, change our curMonth/curYear values
// and output a new header.
if ((date('Y',$event['event_start']) != $curYear) || (date('M',$event['event_start']) != $curMonth))
{
$curMonth = date('M',$event['event_start']);
$curYear = date('Y',$event['event_start']);
// Outputs in 'Jan.2011' style
// You'll just have to deal with this somehow, like you deal with the rest of the stuff
$eventString = $curMonth.".".$curYear;
}
else
$eventString = "";
// Then instead of:
// $the_events[] =
// use
$eventString .=
... rest of your code ...
$the_events[] = $eventString;
}
Related
I have a small PHP page which takes data from MySQL and displays it via PHP in a monthly calendar. I'm having trouble arranging the data properly within an array to get the desired output.
First, I will describe what I would like to happen:
students come to classes on regular days of the week
they can also make or cancel reservations
the calendar also displays days when the school is not open
In order to display this data on the calendar, I use MySQL to output data from a variety of sources, and then input that into an array with PHP, which I sort by date and output.
My issue is, I would like to be able to handle more than one row of data per day, but because I am using the date as the key, I am limited on only displaying one result per day. If I use a loop to append the date with a counter in the key, I get overlapping results in situations where someone made a reservation and then cancelled that reservation on the same day.
As for my code...
First, I check to see if the student is registered in a weekly class, then input that class into the array.
$sql = "SELECT StudentDB.studentid, ClassDB.classID, ClassDB.class_level, ClassDB.class_title, ClassDB.time, ClassDB.teacher, StudentDB.first_name, StudentDB.last_name, StudentDB.payment_amount, ClassDB.day
FROM ClassDB
INNER JOIN RegDB ON ClassDB.classID = RegDB.classid
INNER JOIN StudentDB ON StudentDB.studentID = RegDB.studentid
WHERE StudentDB.studentid = '$studentid'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) { // DISPLAY REGULAR CLASS DATA
$dayofclass = $row['day'];
$class_level = $row['class_level'];
$class_title = $row["class_title"];
$day = $row["day"];
$class_time = $row["class_time"];
$time = $row["time"];
// check which dates match the days of the week and store in an array
for ($i=1;$i<=$n;$i++){
if ($i<10) {
$i = "0" . $i;
}
$day=date("l",strtotime($yearmonth.$i)); //find weekdays
if($day==$dayofclass){
$time = date("H:i",strtotime($row['time']));
$dates[]=$yearmonth.$i;
$datesdata[$yearmonth.$i] = "0";
$timedata[$yearmonth.$i] = $time;
$classiddate[$yearmonth.$i] = $row['classID'];
}
}
}
echo "</table>";
$conn->close();
}
After that, I check for specific reservations (cancelations, irregular reservations, waitlists) and input them into the array:
$lowerlimit = $yearmonth . "01";
$upperlimit = $yearmonth . "31";
$sql = "SELECT AttendanceDB.*, ClassDB.*
FROM StudentDB
INNER JOIN AttendanceDB ON StudentDB.studentid = AttendanceDB.studentid
INNER JOIN ClassDB ON AttendanceDB.classid = ClassDB.classID
WHERE StudentDB.studentid = '$studentid'
AND AttendanceDB.class_time >= '$lowerlimit'
AND AttendanceDB.class_time <= '$upperlimit'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$loopcount = 0;
// store furikae data in the array
while($row = $result->fetch_assoc()) {
$phpdate = strtotime( $row["class_time"] );
$time = date("H:i",strtotime($row['time']));
$mysqldate = date( 'Y-m-d', $phpdate );
$loopcount++;
$mysqldate = $mysqldate . "+" . $loopcount;
// $loopcount++;
// $mysqldate = $mysqldate . "+" . $loopcount;
$previousdate = $mysqldate;
$previousfurikae = $row['furikae'];
if ($row["furikae"] == 3){
$dates[]=$mysqldate;
$datesdata[$mysqldate] = "1";
$timedata[$mysqldate] = $time;
$classiddate[$mysqldate] = $row['classID'];
} elseif ($row["furikae"] == 8 OR $row["furikae"] == 7) {
$dates[]=$mysqldate;
$datesdata[$mysqldate] = "3";
$timedata[$mysqldate] = $time;
} elseif ($row["furikae"] == 2) {
$dates[]=$mysqldate;
$datesdata[$mysqldate] = "2";
$timedata[$mysqldate] = $time;
}
}
}
$conn->close();
Then finally I check the school calendar and input the days off into the array:
$sql = "SELECT *
FROM SchoolScheduleDB
WHERE date >= '$lowerlimit'
AND date <= '$upperlimit'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// store furikae data in the array
while($row = $result->fetch_assoc()) {
$phpdate = strtotime( $row["date"] );
// $time = date("H:i",strtotime($row['time']));
// $mysqldate = date( 'Y-m-d', $phpdate ) . " " . $time;
$mysqldate = date( 'Y-m-d', $phpdate );
$dates[]=$mysqldate;
$datesdata[$mysqldate] = "666";
}
}
$conn->close();
The way I intended it to work was that:
First the regular classes would be input
Then any reservations would overwrite the original plans
And finally the school calendar would overwrite everything
Currently, this functions as it should, but it is limited to displaying 1 result per day, but I would like to be able to display more than 1 result per day for students who come to multiple classes.
Thank you for your help. If I made any mistakes in my question or my question is unclear I will do my best to revise it.
You can make a Sub-Array for each date by using edged brackets:
$data[20180528][] = 'aa';
$data[20180528][] = 'bb';
$data[20180529][] = 'cc';
$data[20180529][] = 'dd';
$data[20180529][] = 'ee';
will give you an Array like this:
20180528 => aa
=> bb
20180529 => cc
=> dd
=> ee
I need to show (today) text if date is today. How do I do that!
I tried everything but cant find the right anwser that's why Im asking here.
Here is the piece of codeI have right now.
$mod_list.= '<ul class="upcoming-events"><li>
<div class="date">
<span><span class="day">'.date($dateformat,$datetime_start).'</span>
<span><span class="month">'.date($datemonth,$datetime_start).'</span>
<span><span class="year">'.date($dateyear,$datetime_start).'</span>
</div>';
I want to show it just behind the last </span>
It is for event calendar and I want to show the text TODAY on the exact day of the event.
Any Ideas?
if(date('Y-m-d',$datetime_start)==date('Y-m-d')){
//it's today! put code here
}else{
//it's not today
}
If you don't use the second parameter in the date() function, it uses the current time. So comparing their date to today is that simple.
Ok, here is the whole Code for what I'm using, it is actualy a droplet for showing the event calendar in my sidebar.
//:Show next #N events
//:
// Get_Concerts
global $database, $wb;
setlocale (LC_ALL, 'sl_SI.UTF-8'); //za vse kategorije
setlocale (LC_TIME, 'sl_SI.UTF-8'); //za datumske funkcije
// Show how many items, defaults to 10?
if ( !isset($max) ){ $max = 10; };
// year and month and section defaults
if(!isset($year)) {$year = date('Y', time()); }
if(!isset($month)) {$month = date('n', time()); }
if(!isset($section_id)) {$section_id = 0 ; }
// Set dateformat to suit your needs, add timeformat if needed
$dateformat = 'd'; // Standard php date formats
$datemonth = 'M'; // Standard php date formats
$dateyear = 'Y'; // Standard php date formats
// Fetch base page link, if event_id = set
$extrasql = '';
$page_id = 0;
$page_link ='';
if ($section_id<>0) {
$extrasql = " section_id = '".$section_id."' AND ";
$sql = "SELECT page_id FROM ".TABLE_PREFIX."sections WHERE section_id = '".$section_id."'";
$result = $database->query($sql);
if ( $result->numRows() > 0 ) {
while( $row = $result->fetchRow() ) {
$page_id = $row['page_id'];
}
}
if ($page_id <> 0) {
$sql = "SELECT link FROM ".TABLE_PREFIX."pages WHERE page_id = '".$page_id."'";
$result = $database->query($sql);
if ( $result->numRows() > 0 ) {
while( $row = $result->fetchRow() ) {
$page_link = page_link($row['link']);
}
}
}
}
// Set start- and end date for query
// $datestart = "$year-$month-1"; ORIGINAL = show all events in this month
$datestart = date("Y-m-d"); // ALTERNATIVE = show all events in this month, starting today
$dateend = "$year-$month-".cal_days_in_month(CAL_GREGORIAN, $month,$year);
$mod_list = "";
// Fetch the items
$sql = "SELECT DAY(date_start) AS day, id, custom1, date_start, time_start, date_end, time_end, name FROM ".TABLE_PREFIX."mod_procalendar_actions WHERE ".$extrasql." date_start >='$datestart' AND public_stat = 0 ORDER BY date_start,time_start LIMIT 0, ".$max." ";
$mod_query = $database->query($sql);
while ( $row =& $mod_query->fetchRow()){
// Build url like : pages/kalendar.php?id=2&detail=1
$page_url = $page_link.'?id='.$row['id'].'&detail=1';
$ds = $row['date_start']." ".substr($row['time_start'],0,5);
$de = $row['date_end']." ".substr($row['time_end'],0,5);
$datetime_start = mktime(substr($ds,11,2),substr($ds,14,2),0,substr($ds,5,2),substr($ds,8,2),substr($ds,0,4));
$datetime_end = mktime(substr($de,11,2),substr($de,14,2),0,substr($de,5,2),substr($de,8,2),substr($de,0,4));
if ($row['time_start'] !== $printTime) {
$printTime = $row['time_start'];
$mod_list.= '<ul class="upcoming-events"><li>
<div class="date"><span><span class="day">'.date($dateformat,$datetime_start).'</span><span><span class="month">'.date($datemonth,$datetime_start).'</span><span><span class="year">'.date($dateyear,$datetime_start).'</span>
</div>';
$mod_list.= '<div class="event-content"><h6>'.$row["name"].'</h6>
<ul class="event-meta"><li><i class="fa fa-clock-o"> </i>'.substr($printTime,0,5).'<sup>h</sup></li>
<!-- <li><i class="fa fa-info-circle"> </i>'.$row["custom1"].'</li> --></ul></div></li></ul>';
}
$mod_list .= "<hr>";
}
$mod_list .= 'Napovednik<br></br>';
return $mod_list;
Here is the link to the site, LINK you'll notice a TEST event which is created for today, I want a little TODAY text to be shown right beside the HOUR on the right.
I hope this helps more, Thank you
R.
I am currently starting a punchclock for our work. This will log employees, In, Lunch Out, Lunch In and Out each day.
I then would like to calculate times each week but specify the week too. So in MySQL lookup all dates in the selected week and then each day calculate the time between IN and OUT minus the lunch.
I can't get my head around how best to do this.
The table looks like:
id | user_id | punch_time | punch_status
The punch status' are:
In = 1
Out = 0
Lunch = 2
This is what i have already which is showing all the results in the past week.
function getTotalHoursThisWeek($week)
{
include("db.php");
$currUser = getUser('id');
if($week == "CURRENT")
{
$query = "SELECT * FROM punch_clock WHERE YEARWEEK(`punch_time`, 1) = YEARWEEK(CURDATE(), 1) && user_id = $currUser";
} else {
$query = "SELECT * FROM punch_clock WHERE YEARWEEK(`punch_time`, 1) = YEARWEEK($week, 1) && user_id = $currUser";
}
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result))
{
echo $row['punch_time']. "<br />";
}
}
This outputs the following:
2015-04-29 17:04:00 - 0
2015-04-29 08:38:03 - 1
2015-04-30 17:20:00 - 0
2015-04-30 09:19:23 - 1
2015-05-01 09:09:47 - 1
2015-05-01 12:36:44 - 2
2015-05-01 12:57:58 - 1
However i would like to then take each day and then calculate the time from In(1) until Out(1) including any entry for Lunch out(2) and then back In(1) for that day.
After that, add them all together to get the total time for that week.
This should put you on the right track.
function getTotalHoursThisWeek($week)
{
/**
* You should consider moving this elsewhere as it seems you are creating
* a database connection every time you hit this function.
*/
include("db.php");
$userId = getUser('id');
/**
* removed the if statement and combined into a single query, easier to maintain
*/
$query = sprintf("SELECT * FROM punch_clock pc WHERE YEARWEEK(pc.punch_time, 1) = YEARWEEK(%s, 1) AND pc.user_id = %d ORDER BY pc.punch_time ASC", $week == "CURRENT" ? "CURDATE()" : "'$week'", $userId);
/**
* consider looking into using PDO or MySQLi instead of the mysql_* functions are they are
* deprecated and should no longer be used
*/
$result = mysql_query($query) or die(mysql_error());
/** time logged in seconds **/
$timeLogged = 0;
$startTime = 0;
$endTime = 0;
while($row = mysql_fetch_array($result))
{
if ($row['punch_status'] == 1) {
$startTime = strtotime($row['punch_time']);
}
if ($row['punch_status'] != 1) {
$endTime = strtotime($row['punch_time']);
$timeLogged += ($endTime - $startTime);
$endTime = null;
$startTime = null;
}
}
/**
* Include the final punch in, if there was no punch out
*/
if ($startTime != null) {
$timeLogged += (time() - $startTime);
$startTime = null;
}
echo sprintf('User %d has logged %d seconds of work', $userId, $timeLogged);
}
There's probably not a great way to do this in MySQL only, because you would need to JOIN the table back to itself, and that JOIN would be extremely complicated.
Instead, I would recommend doing this in PHP. You can do that by keeping a running tab in your result loop:
$intSec = 0; // instantiate the total
$strTimeIn = ''; // This will keep track of the last time a user clocked in
while($row = mysql_fetch_array($result))
{
// Determine if you're in or out
if ($row['punch_status'] === '1') { // you're in -- store this information
$strTimeIn = $row['punch_time'];
} else { // you're clocking out -- add the difference in time to our aggregator
$intSec = $intSec + (strtotime($row['punch_time']) - strtotime($strTimeIn));
}
echo "User has worked for $intSec seconds this week!";
You can convert the number of seconds into hours / minutes / seconds:
gmdate("H:i:s", $intSec);
Or just hours:
$intSec / 3600;
Whatever makes the most sense for your application.
There's a couple of caveats to this approach:
Assumes users clock in, then clock out -- if a user forgets to clock out, this will break
Assumes entires are in order -- add an ORDER BY to your MySQL statement (ORDER BY punch_time)
I was looking for a plugin that allowed only paid members to access certain WP pages and to display the content based on their day of the course (the course is 200 days long). I used PaidMembershipsPro, but I had to modify it to my needs and I post it here in case might be useful for someone else.
If someone buys a different "membership level" it extends it instead of overwriting (I had to make 3 levels for 3 payment plans, 1/3/6 months, I named them all the same but if someone buys 3 months and then another month it reset the duration, so there is a filter for it below). I asked on SO already, but I didn't get an answer, so I wrote the functions myself. It might be bit sloppy though.
the table:
tt_subs s_id(int) s_user(int) s_months(int) s_since(timestamp)
This is the function that puts the data into a table (it takes the duration as days, because all my levels were timed in days)
add_action("pmpro_after_checkout", tt_AddToSubs);
function tt_AddToSubs($user_id){
global $wpdb, $current_user;
$days = $current_user->data->membership_level->expiration_number; //get days from current order
$months = ceil($days/30);
$today = date('Y-m-d H:i:s',strtotime('today midnight'));
$result = $wpdb->get_results("SELECT s_user, s_months, s_since FROM tt_subs WHERE s_user = $user_id", ARRAY_A);
$rowCount = $wpdb->num_rows;
if($rowCount == 0)//if it's a new user
{
$wpdb->insert('tt_subs',array('s_user' => $user_id,
's_months' => $months,'s_since' => $today),
array('%s','%d','%s')
);
}
else
{
$sincedays = ($result[0]['s_months']*30); //counted without the new month
$since = strtotime("-$sincedays days", strtotime('today midnight'));
$newsince = (strtotime($result[0]['s_since']) <= $since ? $since : strtotime($result[0]['s_since'])); //if membership has passed, shift s_since so user is back in his day
$newsince = date('Y-m-d H:i:s', $newsince);
$months += $result[0]['s_months']; //add months to the existing ones
$wpdb->update('tt_subs',
array('s_months' => $months,'s_since' => $newsince),
array( 's_user' => $user_id ), //where array(
'%d', // value1
'%s' // value2
),
array( '%d' ) //where format
);
}
}
this is a filter that I found for extending the memberships instead of overwriting them
add_filter("pmpro_checkout_level", "level_extend_memberships");
function level_extend_memberships($level)
{
global $pmpro_msg, $pmpro_msgt, $current_user;
//does this level expire? are they an existing members with an expiration date?
if(!empty($level) && !empty($level->expiration_number) && pmpro_hasMembershipLevel() && !empty($current_user->membership_level->enddate))
{
//get the current enddate of their membership
$expiration_date = $current_user->membership_level->enddate;
//calculate days left
$todays_date = time();
$time_left = $expiration_date - $todays_date;
//time left?
if($time_left > 0)
{
//convert to days and add to the expiration date (assumes expiration was 1 year)
$days_left = floor($time_left/(60*60*24));
//figure out days based on period
if($level->expiration_period == "Day")
$total_days = $days_left + $level->expiration_number;
elseif($level->expiration_period == "Week")
$total_days = $days_left + $level->expiration_number * 7;
elseif($level->expiration_period == "Month")
$total_days = $days_left + $level->expiration_number * 30;
elseif($level->expiration_period == "Year")
$total_days = $days_left + $level->expiration_number * 365;
//update number and period
$level->expiration_number = $total_days;
$level->expiration_period = "Day";
}
}
return $level;
}
and finally a function that returns the day the user is on
function tt_myDay()
{
global $wpdb;
if(current_user_can('add_users'))
{
return 999;
}
else
{
$resultq = $wpdb->get_results("SELECT s_since, s_months FROM tt_subs WHERE s_user = ".get_current_user_id(), ARRAY_A);
$day = ceil((time() - strtotime($resultq[0]['s_since']))/86400);
return ($day > ($resultq[0]['s_months']*30) ? ($resultq[0]['s_months']*30) : $day );
}
}
I am searching up a database to find the past 7 days worth of data, accumulated.
It works perfectly, but I currently have seven editions of the same code - so I want to loop it somehow, however if I do that, how do I loop it correctly and name the variables. Aside from naming the variables (day_X_) I think I should be able to loop it 7 times fairly easily...
// Get the current day
$graph_day_1_date_lower = date('Y-m-d') . " 00:00";
$graph_day_1_date_upper = date('Y-m-d') . " 23:59";
$graph_day_1_name = date('D') . " (Today)";
/* Successes */
$graph_day_1 = mysqli_query($con,
"SELECT COUNT(`id`) AS num FROM `hidden`
WHERE submittedtime >= '$graph_day_1_date_lower'
AND submittedtime < '$graph_day_1_date_upper'
AND u_s_code='C001'")
or die(mysqli_error($con));
$graph_day_1_row = mysqli_fetch_assoc($graph_day_1);
$graph_day_1_count = $graph_day_1_row['num'];
$graph_total_count = $graph_day_1_count;
/* Errors */
$graph_e_day_1 = mysqli_query($con,
"SELECT COUNT(`id`) AS num FROM `hidden`
WHERE submittedtime >= '$graph_day_1_date_lower'
AND submittedtime < '$graph_day_1_date_upper'
AND u_s_code='E001'")
or die(mysqli_error($con));
$graph_e_day_1_row = mysqli_fetch_assoc($graph_e_day_1);
$graph_e_day_1_count = $graph_e_day_1_row['num'];
$graph_e_total_count = $graph_e_day_1_count;
I will then print the two total counts for each day
Here's what you would want to do:
$today = time(); // or use your upper / lower bounds
$daysToShow = 7;
$dayData = array();
for($i = 0; $i < $daysToShow; $i++){
$dateToCheck = $today + ($i * 24 * 60 * 60); // add a day each time $i goes up
$dataArray = mysql_fetch_assoc($yourDataHere); // replace with your mysqli query using $dateToCheck
$dayData[] = $dataArray; // add to array
}
foreach($dayData as $day){
echo $day['name']; // print out your info here
}