XF 1.5 Post permalinks broken after page shift

PJK

Active member
A user mentioned this issue, and wondering what the best way to solve it is:
The permalink contain a page number. Imagine if the person A posts to the thread 20 times, then the person B will post, copy the permalink to his newest post and save it. The link will look like: "https://www.domain.com/forum/threads/somethread.x/page-y#post-z".
After a little while, a person A decides to delete all his 20 posts. The person's B post will then be on the page (y-1), so when someone opens a permalink, it will lead him to the next page from where the person's B post is now.

Here is what I did:
On the page https://www.domain.com/forum/threads/thread-title-thread.3582/page-767, the first post was by member Joe . I clicked on the post number to get a permalink, and here is what it looked like:
https://www.domain.com/forum/thread-title-thread.3582/page-767#post-1158303
I opened this link in a new incognito window of the browser to see if it works. It opened page 767 of the thread, then the page loaded, then it scrolled to Joe's post, as expected.
Then I opened the previous page (766) and deleted my old post. I reloaded the page 766 and saw Joes's post there, on the last position, as expected (because of the shift). Here comes the interesting part:
I copied new permalink to the Joe's post, it now looks like this and is accessable now:
https://www.domain.com/forum/thread-title-thread.3582/page-766#post-1158303
Then I tried to open an old link, it opened the page 767 as before, but after loading it didn't scroll anywhere obviously because it couldn't find Joe's post on this page anymore. The old permalink became broken.

I suggest using the following format for all permalinks:
https://www.domain.com/forum/posts/530335

What's the best way to prevent permalinks from breaking as described above, and change all the permalinks when copied from the post numbers to the format /forum/posts/xxxx?

Thanks.
 
You would need to edit the template post to change the "permalink" instances to point at the basic "posts" link, though note that you will then also lose any of the contextual elements in the link (notably, the thread title). It'd just be done though a link like:
Code:
{xen:link posts, $post}
 
You would need to edit the template post to change the "permalink" instances to point at the basic "posts" link, though note that you will then also lose any of the contextual elements in the link (notably, the thread title). It'd just be done though a link like:
Code:
{xen:link posts, $post}
I'm unsure why these "permalinks" are built in a way where they break when posts are removed at a later time. It doesn't make sense. Can you explain this logic?

I'm more concerned at preserving working links instead of keeping contextual elements. Ideally I'd like to offer both options. Thanks.
 
Are you having problems with the template modification? The suggested template edit would be the only way to get what you want in XF1 (short of some sort of add-on).

We have changed the approach in XF2 in an attempt to get the best of both worlds though.
 
Are you having problems with the template modification? The suggested template edit would be the only way to get what you want in XF1 (short of some sort of add-on).

We have changed the approach in XF2 in an attempt to get the best of both worlds though.
I haven't made the template modification because it will change all previous URLs again and get rid of ones that are working. What do you suggest I do in this case? Not having permalinks doesn't really make sense (where the URL stops working when people delete posts) - can you explain that to me? Thanks.
 
It will change the previous URLs, but it won't invalidate the ones that work. Indeed, when you click on one of those, it will redirect you to the exact URL that the default code links to.

While it is possible for the issue you're mentioning to happen, it is not something we have only seen rarely and the additional context of the thread info in the URL was something we felt was more beneficial.
 
Noticed that permalinks are finally permanent in xf2 today which is great. I personally try to link to https://forum.domain/posts/post-id in xf1.x which was not an optimal scenario.
 
  • Like
Reactions: PJK
It will change the previous URLs, but it won't invalidate the ones that work. Indeed, when you click on one of those, it will redirect you to the exact URL that the default code links to.

While it is possible for the issue you're mentioning to happen, it is not something we have only seen rarely and the additional context of the thread info in the URL was something we felt was more beneficial.
Thanks, so in the event I want to revert back to the old format, I can without issue, correct? Cheers!
 
There are 2 references to:
Code:
{xen:link threads/post-permalink, $thread, 'post={$post}'}
that need to be changed to:
Code:
{xen:link posts, $post}
in the "post" template.
 
hah. thank you for this. this is one of the few things that really bother me about XF1.x. Made the change on my forum. remains to be seen if google spiders would now start linking to these permalinks or ignore them... 🤷
 
Last edited:
You would need to edit the template post to change the "permalink" instances to point at the basic "posts" link, though note that you will then also lose any of the contextual elements in the link (notably, the thread title). It'd just be done though a link like:
Code:
{xen:link posts, $post}
I went ahead and finally made this change, but the permalinks for posts didn't seem to change. Here is the post template. Any other changes I need to make? Thanks
Code:
<xen:include template="message">

    <xen:map from="$post" to="$message" />

    <xen:set var="$messageId">post-{$post.post_id}</xen:set>
    
    <xen:set var="$likesUrl">{xen:link posts/likes, $post}</xen:set>
    
    <xen:set var="$messageContentAfterTemplate"><xen:if is="{$post.attachments}"><xen:include template="attached_files" /></xen:if></xen:set>
    
    <xen:set var="$messageAfterTemplate">
                
        <div class="messageMeta ToggleTriggerAnchor">
            <div class="privateControls <xen:if is="@xb_message_controls_menu">hiddenResponsiveMedium hiddenResponsiveNarrow</xen:if>">
                <xen:if is="{$post.canInlineMod}"><input type="checkbox" name="posts[]" value="{$post.post_id}" class="InlineModCheck item" data-target="#post-{$post.post_id}" title="{xen:phrase select_this_post_by_x, 'name={$post.username}'}" /></xen:if>
                <xen:if is="@xb_message_layout != 1">
                    <span class="item muted">
                        <span class="authorEnd"><xen:username user="$post" class="author" />,</span>
                        <a href="{xen:link posts, $post}" title="{xen:phrase permalink}" class="datePermalink"><xen:datetime time="$post.post_date" /></a>
                    </span>
                </xen:if>
                <xen:hook name="post_private_controls" params="{xen:array 'post={$post}'}">
                <xen:if is="{$post.canEdit}">
                    <a href="{xen:link posts/edit, $post}" class="item control edit {xen:if $xenOptions.messageInlineEdit, OverlayTrigger}"
                        data-href="{xen:link posts/edit-inline, $post}" data-overlayOptions="{&quot;fixed&quot;:false}"
                        data-messageSelector="#post-{$post.post_id}"><span></span>{xen:phrase edit}</a>
                    <xen:require js="js/xenforo/discussion.js" />
                </xen:if>
                <xen:if is="{$post.edit_count} && {$post.canViewHistory}"><a href="{xen:link posts/history, $post}" class="item control history ToggleTrigger"><span></span>{xen:phrase history}</a></xen:if>
                <xen:if is="{$post.canDelete}"><a href="{xen:link posts/delete, $post}" class="item control delete OverlayTrigger"><span></span>{xen:phrase delete}</a></xen:if>
                <xen:if is="{$post.canCleanSpam}"><a href="{xen:link spam-cleaner, $post}" class="item control deleteSpam OverlayTrigger"><span></span>{xen:phrase spam}</a></xen:if>
                <xen:if is="{$canViewIps} AND {$post.ip_id}"><a href="{xen:link posts/ip, $post}" class="item control ip OverlayTrigger"><span></span>{xen:phrase ip}</a></xen:if>
                
                <xen:if is="{$post.canWarn}">
                    <a href="{xen:link members/warn, $post, 'content_type=post', 'content_id={$post.post_id}'}" class="item control warn"><span></span>{xen:phrase warn}</a>
                <xen:elseif is="{$post.warning_id} && {$canViewWarnings}" />
                    <a href="{xen:link warnings, $post}" class="OverlayTrigger item control viewWarning"><span></span>{xen:phrase view_warning}</a>
                </xen:if>
                <xen:if is="{$post.canReport}">
                    <a href="{xen:link posts/report, $post}" class="OverlayTrigger item control report" data-cacheOverlay="false"><span></span>{xen:phrase report}</a>
                </xen:if>
                
                </xen:hook>
            </div>
            <xen:if is="@xb_message_controls_menu">
            <div class="privateControls visibleResponsiveMedium visibleResponsiveNarrow">
                            <xen:if is="{$post.canInlineMod}"><input type="checkbox" name="posts[]" value="{$post.post_id}" class="InlineModCheck item" data-target="#post-{$post.post_id}" title="{xen:phrase select_this_post_by_x, 'name={$post.username}'}" /></xen:if>
                            <xen:if is="@xb_message_layout != 1">
                                <span class="item muted">
                                    <span class="authorEnd"><xen:username user="$post" class="author" />,</span>
                                    <a href="{xen:link posts, $post}" title="{xen:phrase permalink}" class="datePermalink"><xen:datetime time="$post.post_date" /></a>
                                </span>
                            </xen:if>
                <xen:if is="{$visitor.user_id}">
                <div class="Popup privateControlsPopup item">
                    <a href"#" rel="Menu" class="cloaked" data-closemenu="true"><span class="menuIcon">{xen:phrase menu}</span></a>
                    <div class="Menu JsOnly privateControlsLinks">
                        <div class="primaryContent menuHeader">
                                <h3>{xen:phrase controls}</h3>
                        </div>
                        <ul class="secondaryContent blockLinksList">
                            <xen:hook name="post_private_controls" params="{xen:array 'post={$post}'}">
                            <xen:if is="{$post.canEdit}">
                                <li><a href="{xen:link posts/edit, $post}" class="item control edit {xen:if $xenOptions.messageInlineEdit, OverlayTrigger}"
                                    data-href="{xen:link posts/edit-inline, $post}" data-overlayOptions="{&quot;fixed&quot;:false}"
                                    data-messageSelector="#post-{$post.post_id}"><span></span>{xen:phrase edit}</a></li>
                                <xen:require js="js/xenforo/discussion.js" />
                            </xen:if>
                            <xen:if is="{$post.edit_count} && {$post.canViewHistory}"><li><a href="{xen:link posts/history, $post}" class="item control history OverlayTrigger"><span></span>{xen:phrase history}</a></li></xen:if>
                            <xen:if is="{$post.canDelete}"><li><a href="{xen:link posts/delete, $post}" class="item control delete OverlayTrigger"><span></span>{xen:phrase delete}</a></li></xen:if>
                            <xen:if is="{$post.canCleanSpam}"><li><a href="{xen:link spam-cleaner, $post}" class="item control deleteSpam OverlayTrigger"><span></span>{xen:phrase spam}</a></li></xen:if>
                            <xen:if is="{$canViewIps} AND {$post.ip_id}"><li><a href="{xen:link posts/ip, $post}" class="item control ip OverlayTrigger"><span></span>{xen:phrase ip}</a></li></xen:if>
                            
                            <xen:if is="{$post.canWarn}">
                                <li><a href="{xen:link members/warn, $post, 'content_type=post', 'content_id={$post.post_id}'}" class="item control warn"><span></span>{xen:phrase warn}</a></li>
                            <xen:elseif is="{$post.warning_id} && {$canViewWarnings}" />
                                <li><a href="{xen:link warnings, $post}" class="OverlayTrigger item control viewWarning"><span></span>{xen:phrase view_warning}</a></li>
                            </xen:if>
                            <xen:if is="{$post.canReport}">
                                <li><a href="{xen:link posts/report, $post}" class="OverlayTrigger item control report" data-cacheOverlay="false"><span></span>{xen:phrase report}</a></li>
                            </xen:if>
                            
                            </xen:hook>
                        </ul>
                    </div>
                </div>
                </xen:if>
            </div>
            </xen:if>
            
            <div class="publicControls">
                <xen:if is="@xb_message_layout != 1"><a href="{xen:link posts, $post}" title="{xen:phrase permalink}" class="item muted postNumber hashPermalink OverlayTrigger" data-href="{xen:link posts/permalink, $post}">#{xen:calc '{$post.position} + 1'}</a></xen:if>
                <xen:hook name="post_public_controls" params="{xen:array 'post={$post}'}">
                <xen:if is="{$post.canLike}">
                    <a href="{xen:link posts/like, $post}" class="LikeLink item control {xen:if $post.like_date, unlike, like}" data-container="#likes-post-{$post.post_id}"><span></span><span class="LikeLabel">{xen:if $post.like_date, {xen:phrase unlike}, {xen:phrase like}}</span></a>
                </xen:if>
                <xen:if is="{$canReply}">
                    <xen:if is="{$xenOptions.multiQuote}"><a href="{xen:link threads/reply, $thread, 'quote={$post.post_id}'}"
                        data-messageid="{$post.post_id}"
                        class="MultiQuoteControl JsOnly item control"
                        title="{xen:phrase toggle_multi_quote_tooltip}"><span></span><span class="symbol">{xen:phrase multiquote_add}</span></a></xen:if>
                    <a href="{xen:link threads/reply, $thread, 'quote={$post.post_id}'}"
                        data-postUrl="{xen:link posts/quote, $post}"
                        data-tip="#MQ-{$post.post_id}"
                        class="ReplyQuote item control reply"
                        title="{xen:phrase reply_quoting_this_message}"><span></span>{xen:phrase reply}</a>
                </xen:if>
                </xen:hook>
            </div>
        </div>
    </xen:set>
    
</xen:include>
 
Top Bottom