WHO POSTED TODAY?
a block for IPS forums, by Mousie
Why "who posted"?
You might opt to use a "who posted" block over "who was online" for one of two main reasons:
- You use a Linked Accounts mod that does not record users as being online even if they have posted.
- You want your guests to see not just who visited the site, but who actively participated.
What qualifies as a "post"?
This block makes use of the "member_last_post" column attached to the member row. This generates a new date stamp any time the user posts content on the forum. This includes:
- New posts
- New topics
- New status updates
- New replies to status updates
- New blogs
- New comments to blogs
- New database records
-
New comments to database records
So in effect, any contribution the member makes to the forum is counted as Activity.
How do I install this block?
You'll find the full code at the end of this post. In your ACP:
- Go to Pages --> Blocks
- Create New Block
- Select "type" as "Custom"
- Select "content editor" as "Manual PHP"
- Under "Details", give your block a name, description, and a template key.
- Under "Content", copy and paste the code at the end of this post.
How do I display this block?
This block is mainly designed to sit at the bottom of your forum, similar to how Who Was Online? does. You can display the block by:
- Opening the Page Builder menu using the > icon on the left side of your screen, and selecting the block to drag and drop where you would like it displayed.
- If you defined a template key, you can add the block by editing the page template and placing the "{block="my_block_key"}" in your HTML templates where you would like the block to display.
If you can use Page Builder to get the block where you want it, that is usually the simplest method.
How does it work?
This block doesn't use data from any custom databases, so it should work for most IPS forums. You should be able to copy and paste it into a new block, place it on your forum, and it will work.
However, when I began coding blocks I found it difficult to find examples of simple blocks that I could understand, and use to modify and build my own blocks. For that reason, I've broken down the code below to explain what each function does, and how it manipulates the data to get the desired result.
1. Establishing the time difference
$rightnow = time(); $timevar = $rightnow - 86400;
- In the first line, we use the time() function to generate a unix timestamp - a number that is essentially a count of how many seconds have passed since 1/1/1970. As the function is undefined (there is no additional information between the parenthesis), it defaults to current time. It also says that whenever we use the variable $rightnow, that it is to use the datestamp created by the time function in that first line.
- In the second line, we instruct the system to subtract 86400 seconds from $rightnow, and call that number $timevar.
Basically, we're asking the system to work out what the time is now, and take 24 hours off it. You can adjust that "86400" to whatever number you like, depending on what range you would like displayed on your block. Want posts from the past week? Subtract 604800 instead.
2. Accessing the member database
// Get the select object
$select = (\IPS\Db::i()->select('member_id, prefix, suffix, g_id, name, members_seo_name, member_group_id, member_last_post', 'core_members' ));
Here we define a new variable, $select, that we will use to contain information from the member database. The important parts here are:\
- $select - This is the variable that will store all of the information found by the select query below.
- (\IPS\Db::i() - This function, unique to IPS systems, tells the system that we're going to access information from the database. It's a nifty shortcut.
- ->select - This tells the system that we're going to choose some information from a particular database and store it in the $select variable we defined at the start of the line.
-
In the parenthesis, we have the conditions of the select. The format is: ('{columns to select}', '{database}')
There are other conditions that you can add to manipulate and refine your data, but this simple example only defines the columns and database. You can also use * as a wildcard to select all information from a particular database, eg select('*', 'core_members') will return all columns of information from the core_members table.
3. Join on group data
$select = $select->join( 'core_groups', 'core_members.member_group_id=core_groups.g_id', 'LEFT');
This line is important if you want to style the output using the group colours you've defined in your system. Which you probably do, because it looks nifty. How this works, is it looks at both the core_members table, and the core_groups table (where all information about the groups is stored, including styling) and asks it to find where the member_group_id (from core_members) is the same as g_id (from core_groups). Then, in any row in core_members where those fields are the same, it adds columns to the row and populates them with the relevant data from core_groups.
Sounds complicated, but you can see how it works in a plain SQL example.
Important parts of this function are:
- $select - This is the same variable we used above.
- $select-->join - This says that we're going to take the data from the $select variable we created, and join more data on. Basically, we're updating the information contained in $select, and still calling that updated variable $select.
- In the parenthesis, again we have a set of conditions that will tell the system what data to find and how to join it. The format is ('{second_database}', '{first_database_column}={second_database_column}')
4. Begin the print
print "<div class='ipsWidget ipsWidget_horizontal ipsBox'><h3 class='ipsType_reset ipsWidget_title'>Who Posted Today</h3><div style='padding: 10px;'>";
Here we start to build the HTML that will contain the information. The function "print" is an output function, it tells the system that what comes next is a visual output element. In PHP, you can use HTML code by encasing it in double quotation marks, as in the example above. To print the results of PHP variables, they must be placed outside of the quotation marks. You'll see more of that below.
5. Start analysing the data
foreach( $select as $students ) { if ($students['member_last_post'] > $timevar)
Here, we ask the system to look through each row in $select and compare it to a particular condition.
- foreach - This tells the system that we're not looking at $select as a whole, but each individual row contained within it ($select is essentially a table in itself, created by the data you have chosen).
- $select as $students - This tells the system that each $select row is now going to be called $students, allowing it to differentiate between $select the big group of data, and $students the row of data contained within.
- if - This tells the system that we're only going to proceed for rows that meet the conditions defined in the parenthesis.
- ($students['member_last_post'] > $timevar) - This is our condition. What it says is that any $students row where the column member_last_post (you'll remember this is the column that keeps the latest post datestamp) contains a higher value than $timevar (the variable defined at the beginning of the block) are going to be used in the next processes. $students rows that do not have a datestamp higher than $timevar (thus, did not post in the last 24 hours) will be skipped over.
6. Create a running count
{ $count = $count + 1;
We also want to know how many people have posted today, so this keeps track. Every time a record is found that meets the condition, $count (which initially starts at 0) goes up by +1. This works because it is located inside the foreach, and after the if -- which means that it runs every time a record is found that meets the conditions of the if.
7. Print the member list
print "<a href='/profile/" . $students['member_id'] . "-" . $students['members_seo_name'] . "'>" . $students['prefix'] . $students['name'] . $students['suffix'] . "</a>, "; }}
Again we're using the print function, this time to create a linked and styled list. It looks a touch confusing, and may help if formatted like this.
print "<a href='/profile/" . $students['member_id'] . "-" . $students['members_seo_name'] . "'>" . $students['prefix'] . $students['name'] . $students['suffix'] . "</a>, "; }}
Here you can see more clearly where HTML is enclosed in quotation marks, and where PHP variables are being used. PHP variables are being used to help create the link itself, by accessing the member_id and members_seo_name columns. You can see again how the column name is defined after $students to get the right piece of data, eg $students['name'] returns the name of the account, while $students['member_id'] returns the member's id number.
You can also see how the PHP variables are used when HTML is also being used. If you just want to print the contents of a variable, normally you would use
print $variable;
But because we want to mix PHP and HTML output, we need to do things a little differently. Any PHP variable that is used between or after a HTML sequence needs to have leading and following full stops. For instance:
print "some html" . $variable . "some more html";
8. Print the count and close off
print "<br><span class='resultxc'>" . $count . " members posted today</span><br>"; print "</div></div>";
This simply prints the $count variable (the number of total people that posted in the last 24 hours), and closes off the rest of the HTML used throughout the block.
Who Posted Today -- Block Code
/** * Build SELECT statement * * @param array|string $columns The columns (as an array) to select or an expression * @param array|string $table The table to select from. Either (string) table_name or (array) ( name, alias ) or \IPS\Db\Select object * @param array|string|NULL $where WHERE clause - see \IPS\Db::compileWhereClause() for details * @param string|NULL $order ORDER BY clause * @param array|int $limit Rows to fetch or array( offset, limit ) * @param string|NULL|array $group Column(s) to GROUP BY * @param array|string|NULL $having HAVING clause (same format as WHERE clause) * @param int $flags Bitwise flags * @li \IPS\Db::SELECT_DISTINCT Will use SELECT DISTINCT * @li \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS Will add SQL_CALC_FOUND_ROWS * @li \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS Will return the result as a multidimensional array, with each joined table separately * @li \IPS\Db::SELECT_FROM_WRITE_SERVER Will send the query to the write server (if read/write separation is enabled) * @return \IPS\Db\Select * */ $rightnow = time(); $timevar = $rightnow - 86400; // Get the select object $select = (\IPS\Db::i()->select('member_id, prefix, suffix, g_id, name, members_seo_name, member_group_id, member_last_post', 'core_members' )); $select = $select->join( 'core_groups', 'core_members.member_group_id=core_groups.g_id', 'LEFT'); print "<div class='ipsWidget ipsWidget_horizontal ipsBox'><h3 class='ipsType_reset ipsWidget_title'>Who Posted Today</h3><div style='padding: 10px;'>"; foreach( $select as $students ) { if ($students['member_last_post'] > $timevar) { $count = $count + 1; print "<a href='/profile/" . $students['member_id'] . "-" . $students['members_seo_name'] . "'>" . $students['prefix'] . $students['name'] . $students['suffix'] . "</a>, "; }} print "<br><span class='resultxc'>" . $count . " members posted today</span><br>"; print "</div></div>";
- 3