Pinned Posts Download 7.1dev4

German Michael Zülsdorff 8 months ago

Pinned Posts

An example of step-by-step development
release 7.1dev4: ready to use + 8 selectable background colors + language files

NOT to be used in production environments
release 7.1dev3: pinned posts being removed from original location + crash debug
release 7.1dev2: pinned posts appear on top of the newsfeed
release 7.1dev1: admin backend to save post ids + basic placement on top of newfeed

The idea of this component is to pin one or more selected posts on top of the newsfeeds as requested here:

How to pin one or more posts:
1 - Click the date of the post you want to pin:

enter image description here

This will open a new page with the ID of that post (346 in this example)

enter image description here

2 - Keep that ID in mind (write it down ... whatever ...)
3 - Proceed to your administrator page -> Configure -> PinnedPosts

enter image description here

4 - Enter the ID and save it

enter image description here

The first release of this component (7.1dev1) is implementing the basic placement of pinned posts and was derived from the Site Announcement component. No wonder that the result will look very much the same:

enter image description here

Now, that we have the post ID of interest already in place, the next task is to make use of it, fetch that post and display it.

Release 7.1dev2 comes implemented with the code to pin the actual post(s) now - using the ids which were saved via Configure -> PinnedPosts

See posts.php for more details...

So here's pinned post 346 again that I picked as an example:
enter image description here

German Dominik L Replied 3 weeks ago

I found an issue;

Normally comments are collapsed, but when using this component, comments on pinned posts are full length

German Michael Zülsdorff Replied 2 months ago

I'm sorry, but currently I have no time for giving detailed help or larger coding projects.
As a starting point I would clone parts of the Group Invitation component into Pinned Posts in order to get an input field in place, change the 'Invite' button to 'Save' which would call an action to store the post ids. The remaining group 'pin' logic should be adaptable from the already existing code.

Bulgarian Georgi Shindarov Replied 2 months ago

Hello again. I want to ask if it is possible for the Pinned Posts component to be modified to a Group Pinned Posts component so that any user who is a group administrator can change the order of posts in the group. I need this because I want to make a music ranking.. and not only that.. it can also be a ranking of images that can be changed by the administrator depending on the number of likes on clips or images.. Is it possible to help me I will do it.. or you can do it.. if you think it will be faster and easier.. I think such a component would be useful..

enter image description here

German Michael Zülsdorff Replied 7 months ago

Oops, I thought it would be obvious when I wrote that I intentionally changed Arsalan's line of valid code

$return['order_by'] = 'o.guid ASC';

to this invalid line

$return['order_by'] = 'CRASH_ME!';

in order to force some debug output....

Okay, it was not. Then, what can we do?

1) Revert back to Arsalan's original code. But that would change the sort order in general. And that's not what you wanted.
2) Leave Arsalan's line in place but reverse the ordering in a valid way like

$return['order_by'] = 'o.guid DESC';

which wouldn't hurt but doesn't make too much sense because the default ordering is already DESCENDING
3) simply remove the invalid line :)

Bulgarian Georgi Shindarov Replied 7 months ago

Ok, what needs to be done next to get the component working?

German Michael Zülsdorff Replied 7 months ago

Yeah, what should happen next ... A closer look under the hood and a little explaining can't be bad, I think. ;)

So, let's recall what Arsalan suggested 2 weeks ago. His idea was using 3 hooks calling a function to simply reverse the default DESCENDING sort order to get the oldest post on top like:

function wall_posts_order($hook, $type, $return, $params){
                $return['order_by'] = 'o.guid ASC';
                return $return;

But since this didn't solve exactly what you wanted, we found a different way with release dev1 and dev2 to pin the post on top - using some code from the Site announcement component and the page handler of OssnWall.
Next, you requested to hide the original post - and that's where Arsalan's idea comes into conclusion again. Just a little changed - not to reverse the sort order but exclude the pinned posts instead.
Time to open ossn_com.php of this component now, and see what has changed:

if (isset($settings->PinnedPosts) && !empty($settings->PinnedPosts)) {
    // yes we have!
    // so let's extend the original SQL query to exclude these post ids
    $return['wheres'] = "o.guid NOT IN ({$settings->PinnedPosts})";
    // and stop here and see how the resulting query looks like ....
    $return['order_by'] = 'CRASH_ME!';
    return $return;

Aside from some checking if there are pinned posts at all, it's actually just one line to get that accomplished:

$return['wheres'] = "o.guid NOT IN ({$settings->PinnedPosts})";

Okay, but how do these wheres have an impact on fetching wall posts? In order to get a better understanding I decided to leave Arsalan's former line in place and change 'ASC' to 'CRASH_ME'. That's in fact no valid SQL the database could handle and hence throwing the error message:

OssnDatabaseException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CRASH LIMIT 0, 10' at line 1 

SELECT DISTINCT  o.guid, o.time_created FROM ossn_object as o JOIN ossn_entities as e0 ON e0.owner_guid=o.guid JOIN ossn_entities_metadata as emd0 ON e0.guid=emd0.guid JOIN ossn_entities as e1 ON e1.owner_guid=o.guid JOIN ossn_entities_metadata as emd1 ON e1.guid=emd1.guid WHERE(o.subtype='wall' AND o.type='user' AND (e0.type='object' AND e0.subtype='access' AND (1=1) AND e1.type='object' AND e1.subtype='poster_guid' AND (emd0.value=2 OR emd0.value=3)) AND o.guid NOT IN (156))  ORDER by o.guid CRASH LIMIT 0, 10; 

Let's have a closer look at the query above:
Initially, the query would fetch ALL ids from the ossn_object table:

SELECT DISTINCT  o.guid, o.time_created FROM ossn_object ...

but then there are a lot of extra conditions to sort out those records which are actually posts:

WHERE(o.subtype='wall' AND o.type='user' AND (e0.type='object' AND e0.subtype='access' AND (1=1) AND e1.type='object' AND e1.subtype='poster_guid' AND (emd0.value=2 OR emd0.value=3)) AND o.guid NOT IN (156))

And now it becomes clear, which way the code

$return['wheres'] = "o.guid NOT IN ({$settings->PinnedPosts})";

was 'translated' to SQL and added to all other wheres at the end as

AND o.guid NOT IN (156)

with your post 156 which was already pinned and needs to be excluded from the original location on the wall as requested by you.

Bulgarian Georgi Shindarov Replied 7 months ago

Yes.. apparently this is some kind of test.. and what should happen next?

German Michael Zülsdorff Replied 7 months ago

Yep, this release leads to a crash - that's why I named it "the_crasher" :)
Thanks for sending the error report. So, the id of your pinned post is 156?

Bulgarian Georgi Shindarov Replied 7 months ago

Unfortunately there is some problem and the component is not working properly.. I am attaching an image

enter image description here

German Michael Zülsdorff Replied 7 months ago

I have implemented the hooks as suggested by Arsalan in release 7.1dev3_the_crasher now.
See ossn_com.php for details


Developer: Michael
License GPL v2
Type: Site admin
Requires Ossn Version : 7.1
Latest Version: 7.1dev4
Last Updated 7 months ago
Repository Url View Repository