0

I would like to know how I could get the offset of a custom post or its page, outside the get_posts loop.

I developed an external web application which connects to the wordpress blog with JSON API plugin, and show a given posts page using an AJAX request like :

?json=get_posts&orderby=date&order=desc&count=x&page=n

(This will return the nth page of x posts)

This works well, but now I would like to set a link on the wordpress blog "single post" page to this application, like "Show this post in app", with the current page offset as parameter. So I will be able to read this param in the app and get posts of the page containing the post, and highlight this post (sent as parameter).

If I can get the offset, I will be able to show the right page with a modulo operator :

If offset = 22 and count = 10, show page 3 and highlight post n°2

page = Math.ceil(offset / count);
post_to_highlight_position = offset % count;

Do you know how I could do that? or if there is a better way to achieve this?

4 Answers 4

1

I don't think that you can get an offset of the page outside of the loop, since it will be out of the context. Offset may vary depending on the arguments you are using to get posts for the loop.

Easiest solution will be to calculate offset in the app. You will need to pass post_id as an attribute and then loop through all the posts obtained by ?json=get_posts&orderby=date&order=desc&count=x&page=n and compare their IDs to the one you got as an attribute.

Hope it makes sense.

1
  • I finally used a custom sql query to get the offset by getting every posts offsets and filtering by id, instead of looping every posts directly in javascript which would be much heavier, but thanks for the suggestion !
    – risk
    Dec 11, 2013 at 9:16
1

The "offset" depends on the query-- sort order, conditions like category or tag, meta queries, etc.--, and it changes every time a post is added to the blog. It isn't something you "get" so much as something you calculate.

On a "single post" page the query is pretty straightforward and returns a single post-- that is, 0 offset. Assuming what you want is the offset in the archive, you'd have to run that archive query (with whatever parameters apply) and loop through the results until you find the post you want. That is a pretty heavy load on the server.

There is this rather complex query-- no idea if it works: https://stackoverflow.com/q/3614666/1735890 You'd have to convert that to WordPress.

1
  • Thanks for your answer, I just succeeded to do what I wanted with something similar to this query. I just posted the complete working procedure as an answer :)
    – risk
    Dec 11, 2013 at 9:09
0

Thank you for you answers, I finally succeeded to do what I wanted with a custom SQL query :)

Here is how I achieved this : First, I got the SQL query generated with WP_QUERY by adding this code :

$query = new WP_Query( $query_args );

//write the SQL query
echo $query->request;

I got something like :

SELECT wp_posts.ID 
FROM wp_posts 
WHERE 1=1 
AND wp_posts.post_type = 'work' 
AND (wp_posts.post_status = 'publish') 
ORDER BY wp_posts.post_date DESC

Which returns the complete list of posts, ordered by newest first. Then I added the offset by simply declaring an offset variable and increment it in every row, like that :

SET @offset=0;
SELECT wp_posts.ID, 
       @offset := @offset + 1 AS offset
FROM wp_posts 
WHERE 1=1 
AND wp_posts.post_type = 'work' 
AND (wp_posts.post_status = 'publish') 
ORDER BY wp_posts.post_date DESC

Last step, I filtered this list of ID + offset associations by post ID and add the custom rows (page and position) :

SET @offset=0;
SELECT ID, 
       offset - 1 AS offset, 
       CEIL(offset / 10) AS page,
       (offset - 1) % 10 AS position
FROM (SELECT wp_posts.ID, 
      @offset := @offset + 1 AS offset
      FROM wp_posts 
      WHERE 1=1 
      AND wp_posts.post_type = 'work' 
      AND (wp_posts.post_status = 'publish') 
      ORDER BY wp_posts.post_date DESC) 
      AS OFFSETS
WHERE ID = 83

(where 83 is the searched post ID and 10 the number of posts per page)

I used offset - 1 AS offset to get offsets from 0, but you can just use offset to get offsets from 1.

So this will return the following tables :

id=83, posts per page = 10 :

ID | offset | page | position
83 |   16   |  2   |    6    

-> 6th position on page 2

id=10, posts per page = 5 :

ID | offset | page | position
10 |   33   |  7   |    3    

-> 3th position on page 7

I hope this will help someone ! :)

0

This is for a little bit of a different problem set, and I don't know how active this is, but I came across it trying to solve a similar problem and wanted to share my solution for anyone that might come across this post in the future.

I basically assumed I'd need to process the information as temkin described in his answer. I added this function to my functions.php file and then called it in my single.php file and stored it as a $page_number variable. Since I now had the proper page number, I could just append it to the post archive URL in the link.

Note that you'd just need to update the query $args to reflect the same parameters that your archive page is using.

In functions.php

function get_archive_page_num( $post_id ){

$post_type = get_post_type( $post_id );
$index = '';
$archive_page_number = '';
$per_page = get_option('posts_per_page');

$args = array(
    'post_type' => $post_type,
    'posts_per_page' => -1,
    'orderby' => 'date',
    'order' => 'DESC'
);

$posts = get_posts( $args );
foreach($posts as $key=>$post){
    $this_id = $post->ID;

    if($this_id === $post_id){
        $index = $key;
        $archive_page_number = ceil( $index / $per_page );
    }
}

    return $archive_page_number;    
}

In whatever file you need the pagination link for - single.php, for example

$post_id = $post->ID
$post_page = get_archive_page_num( $post_id );
$link = get_post_type_archive_link( $post->post_type );


echo "<a href='$link/page/$post_page>Back to Archive</a>";

This will at least get you the proper page number. If you want to go back and have the page display on the specific post - you could just add an ID attribute to each post listing that uses the $post->ID and append an anchor tag from the single page. That addition would look like this:

$post_id = $post->ID
$post_page = get_archive_page_num( $post_id );
$link = get_post_type_archive_link( $post->post_type );
$post_anchor = "post-$post_id";

echo "<a href='$link/page/$post_page/#$post_anchor>Back to Archive</a>";

If the $post->ID = 1234, this would anchor to an element on the archive page with id="post-1234", should it exist. Hope this helps someone!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.