• Resolved Beee

    (@beee)


    I have created a profile page for all users in our database with author.php, see an example on https://internationaldownhillfederation.org/member/berry-plasman/

    I am now developing a new website where I’m using query vars to create ‘fake’ sub-pages, such as

    • https://internationaldownhillfederation.org/member/berry-plasman/race-attendance/ (which races he/she attended)
    • https://internationaldownhillfederation.org/member/berry-plasman/written/ which posts he/she wrote (what’s normally shown on an author page)
    • https://internationaldownhillfederation.org/member/berry-plasman/mentioned/ to show in which posts he/she got mentioned

    Note: links are not working on live site (except first one).

    The last one is the one which is giving me issues. I used ACF to be able to tag users in a normal post. On /mentioned/ I query the posts in which he/she got mentioned. That is not a problem.

    The problem lies in the fact that I need to paginate these ‘mentioned’ posts BUT since 99% of the users have not written any posts, a paged author page returns a 404 because there are no posts for that user and thus no page 2.

Viewing 15 replies - 1 through 15 (of 26 total)
  • Thread Starter Beee

    (@beee)

    I tried working with pre_get_posts to override the query (and the authors), since an author page only shows posts from author X… but no luck…

    Thread Starter Beee

    (@beee)

    I think if I can override the authors, it should be able to do, but this doesn’t work (yet) on an author page.

    Moderator keesiemeijer

    (@keesiemeijer)

    Did you create the rewrite rules for those pages (e.g. member/berry-plasman/race-attendance/)? Or is this the problem?

    How did you change the author archive slug /author to /member?

    Can you show us what you have working so far

    Moderator keesiemeijer

    (@keesiemeijer)

    I’ve extended the author archive pages with extra pages on a website before. I’m not sure this is what you need, but here’s how I did it. Try putting the following in your (child) theme’s functions.php file:

    
    function ap_author_pages_get_page_query_vars() {
    	// Array with extra author archive page slugs
    	return array(
    		'race-attendance',
    		'written',
    		'mentioned',
    	);
    }
    
    add_filter( 'query_vars', 'ap_author_pages_add_query_var' );
    function ap_author_pages_add_query_var( $query_vars ) {
    	// Add a new query var to the public query vars.
    	$query_vars[] = 'author_page';
    	return $query_vars;
    }
    
    add_action( 'generate_rewrite_rules', 'ap_author_pages_generate_rewrite_rules' );
    function ap_author_pages_generate_rewrite_rules( $wp_rewrite ) {
    	// Get the new author pages rewrite rules.
    	$rules = ap_author_pages_get_rewrite_rules();
    
    	if ( is_array( $wp_rewrite->rules ) && ! empty( $rules ) ) {
    		// Add the author page rewrite rules.
    		$wp_rewrite->rules = $rules + $wp_rewrite->rules;
    	}
    }
    
    function ap_author_pages_get_rewrite_rules() {
    	global $wp_rewrite;
    
    	$author_permastruct = $wp_rewrite->get_author_permastruct();
    	if ( ! $author_permastruct ) {
    		return array();
    	}
    
    	$query_vars    = ap_author_pages_get_page_query_vars();
    	$rewrite_rules = array();
    
    	foreach ( $query_vars as $query_var ) {
    		// Get the author page query permastruct.
    		$permastruct = "{$author_permastruct}/{$query_var}";
    
    		// Generate the rewrite rules for the new author page.
    		$rules = $wp_rewrite->generate_rewrite_rules( $permastruct );
    
    		// Get the rewrite rules for the query var only.
    		$rules = ap_author_pages_get_query_var_rewrite_rules( $rules, $query_var );
    
    		// Add the rewrite rules.
    		$rewrite_rules = $rules + $rewrite_rules;
    	}
    
    	return $rewrite_rules;
    }
    
    function ap_author_pages_get_query_var_rewrite_rules( $rules, $query_var ) {
    	global $wp_rewrite;
    
    	// New author page rewrite rules.
    	$query_var_rules = array();
    
    	// Default match for an author archive query.
    	$author_match = $wp_rewrite->index . '?author_name=' . $wp_rewrite->preg_index( 1 );
    
    	foreach ( $rules as $rule => $match ) {
    		// Check if the query var is in the rule
    		if ( false === strpos( $rule, $query_var ) ) {
    			continue;
    		}
    
    		// Check if the author match is in the match
    		if ( false === strpos( $match, $author_match ) ) {
    			continue;
    		}
    
    		// Add <code>author_page</code> query var to the match.
    		$new_match = $author_match . "&author_page={$query_var}";
    
    		// Update the match for the rewrite rule.
    		$query_var_rules[ $rule ] = str_replace( $author_match, $new_match, $match );
    	}
    
    	return $query_var_rules;
    }

    This will add those extra pages and pagination rules if needed. You’ll need to re-save your permalinks at wp-admin > Permalinks before you can visit the pages.

    You can then update the query for these pages with the pre_get_posts action.

    Example:

    
    add_action( 'pre_get_posts', 'ap_author_pages_query' );
    
    function ap_author_pages_query( $query ) {
    
    	// Do nothing with the query if:
    	//     It's a query in the wp-admin
    	//     it's not the main query for an author archive page
    	if ( is_admin() || ! ( $query->is_main_query() && is_author() ) ) {
    		return;
    	}
    
    	$author_page =  $query->get( 'author_page' );
    
    	if ( ! $author_page ) {
    		// Normal author archive page
    		// page = /member/author-name
    	}
    
    	if ( 'race-attendance' === $author_page ) {
    		// page = /member/author-name/race-attendance
    	}
    
    	if ( 'written' === $author_page ) {
    		// page = /member/author-name/written
    	}
    
    	if ( 'mentioned' === $author_page ) {
    		// page = /member/author-name/mentioned
    	}
    }

    I hope this gets you in the right direction.

    btw:
    consider creating a child theme instead of editing your theme directly – if you upgrade the theme all your modifications will be lost. Or create a plugin with the code above.

    Just a note that there are also plugins you can use to create a child theme:
    https://www.ads-software.com/plugins/search/child+theme/

    Thread Starter Beee

    (@beee)

    @bdbrown thanks for the response, but my theme is 100% custom and not available anywhere else, so there’s no child theme.

    @keesiemeijer thanks for the response.

    I do want to mention I use Timber instead of plain PHP. Now in reply to your question.

    I have made the website available @ https://new.internationaldownhillfederation.org.
    The profile I am testing with is https://new.internationaldownhillfederation.org/member/emily-pross/.
    As you can see all subpages work.

    That is not the issue, that all works. It is when a user has NOT written any posts and I want to ‘reach’ a paged (author) page.
    Emily has not written any posts so a paged author page does not exist. That is what I want to ‘fake’.

    You can see it at my own profile: https://new.internationaldownhillfederation.org/member/berry-plasman/written/
    Those are the posts written by me and the actual posts of an author page, with pagination.

    The author archive slug was changed as follows:

    function change_author_permalinks() {
            global $wp_rewrite;
            $wp_rewrite->author_base = 'member';
            $wp_rewrite->flush_rules();
        }
        add_action( 'init', 'change_author_permalinks' );

    These are my rewrite rules:

    function idf_rewrite_profile_pages() {
            add_rewrite_rule( 'member/([a-z-]+)/([a-z-]+)/?$', 'index.php?author_name=$matches[1]&subpage=$matches[2]', 'top' );
            add_rewrite_rule( 'member/([a-z-]+)/mentioned/page/([0-9]+)/?$', 'index.php?paged=$matches[2]&author_name=$matches[1]&subpage=mentioned', 'top' );
            add_rewrite_rule( 'member/([a-z-]+)/written/page/([0-9]+)/?$', 'index.php?paged=$matches[2]&author_name=$matches[1]&subpage=written', 'top' );
        }
        add_filter( 'init', 'idf_rewrite_profile_pages', 1, 3 );

    This checks if a member is ‘tagged’ in any posts

    $rows = $wpdb->get_results( $wpdb->prepare( "
                SELECT *
                FROM {$wpdb->prefix}postmeta
                WHERE meta_key LIKE %s
                AND meta_value = %s
                ", 'idf_tagged_riders_%_member', // meta_name: $ParentName_$RowNumber_$ChildName
            $user_id
        ) );
    
        if ( $rows ) {
            $post_ids  = array();
            foreach ( $rows as $row ) {
                $post_ids[] = intval( $row->post_id );
            }
            
            $ppp       = 14;
            $pages     = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
            $offset    = ( get_query_var( 'paged' ) ) ? (( get_query_var( 'paged' ) - 1 ) * $ppp ) : false;
            
            $mentioned_args         = array(
                'posts_per_page' => -1,
                'post__in'       => $post_ids,
                'orderby'        => 'date',
                'order'          => 'DESC',
            );
        
            $context[ 'mentioned' ] = get_posts( $mentioned_args );
            $amount_posts           = count( $context[ 'mentioned' ] );
            $amount_pages           = intval( round( count( $context[ 'mentioned' ] ) / $ppp ) );
            
            if ( $amount_pages > 1 ) {
                $context[ 'mentioned_paging' ] = true;
        
                $big          = 999999999; 
                $args         = array(
                    'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
                    'format'    => '/page/%#%',
                    'total'     => $amount_pages,
                    'current'   => max( 1, get_query_var( 'paged' ) ),
                    'show_all'  => false,
                    'end_size'  => 3,
                    'mid_size'  => 2,
                    'prev_next' => true,
                    'prev_text' => __( '&laquo; Previous' ),
                    'next_text' => __( 'Next &raquo;' ),
                    'type'      => 'list',
                );
                $context[ 'pagination' ] = sprintf( '<div class="paginator">%s</div>', paginate_links( $args ) );
            }
        }

    This is my pre get posts:

    function alter_query_for_author_mentioned_subpages( $query ) {
            if ( ! is_admin() && $query->is_main_query() && is_author() && 'mentioned' == get_query_var( 'subpage' ) && false != get_query_var( 'paged' )) {
                
                $member_name = $query->query[ 'author_name' ];
                $user_id     = get_user_by( 'slug', $member_name )->ID;
                
                global $wpdb;
                $rows = $wpdb->get_results( $wpdb->prepare( "
                    SELECT *
                    FROM {$wpdb->prefix}postmeta
                    WHERE meta_key LIKE %s
                    AND meta_value = %s
                    ", 'idf_tagged_riders_%_member', // meta_name: $ParentName_$RowNumber_$ChildName
                    $user_id
                ) );
        
                if ( $rows ) {
                    
                    $paged    = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
                    // when var_dumped on /member/emily-pross/mentioned/page/2/, output shows correct page number
    
                    $post_ids = array();
                    foreach ( $rows as $row ) {
                        $post_ids[] = intval( $row->post_id );
                    }
        
                    $authors   = get_all_authors_ids();
                    $authors[] = $user_id;
                    
                    $query->set( 'author__in', $authors );
                    $query->set( 'post__in', $post_ids );
        
                }
            }
        }
        add_action( 'pre_get_posts', 'alter_query_for_author_mentioned_subpages' );

    Any thoughts ?

    • This reply was modified 6 years, 11 months ago by Beee.
    Thread Starter Beee

    (@beee)

    I notice now, the page becomes unavailable due to insufficient memory… but only on the /mentioned subpage (for Emily). Not on mine.

    Thread Starter Beee

    (@beee)

    Hmmm…not sure where I was going with that child theme suggestion. Clearly not applicable to your post. Sorry about the sidetrack.

    Thread Starter Beee

    (@beee)

    All good ??

    Moderator keesiemeijer

    (@keesiemeijer)

    Try adding the query var subpage to the public query variables.

    
    function idf_add_query_vars( $query_vars ) {
    	$query_vars[] = 'subpage';
    	return $query_vars;
    }
    add_filter( 'query_vars', 'idf_add_query_vars' );
    

    You can reset the paged query var in the pre_get_posts action. Here is an example:

    
    function alter_query_for_author_mentioned_subpages( $query ) {
    	if ( ! is_admin() && $query->is_main_query() && is_author() ) {
    
    		$subpage = get_query_var( 'subpage' );
    
    		if ( ( 'mentioned' === $subpage ) && $query->is_paged() ) {
    			// Reset query var paged
    			$query->set( 'paged', '' );
    		}
    	}
    }
    add_action( 'pre_get_posts', 'alter_query_for_author_mentioned_subpages' );
    

    I’m not sure that’s what you want to do as you can now visit all paged pages (/page/2 page/3 etc.).

    Thread Starter Beee

    (@beee)

    Query vars are already added, because it’s used for other things as well.

    function add_vars( $vars ) {
        $vars[] = "continent";
        $vars[] = "subpage";
        $vars[] = "category";
        $vars[] = "booking_id";
    
        return $vars;
    }
    add_filter( 'query_vars', 'add_vars' );

    For some more clarity I added the full files to pastebin:
    author.php – https://pastebin.com/W65iML2X
    pre-get-posts.php – https://pastebin.com/vvkPkEw7

    This is the relevant part of the rewrites (bit updated for usernames)

    function idf_rewrite_profile_pages() {
        add_rewrite_rule( 'member/([a-zA-Z0-9_-]+)/([a-z-]+)/?$', 'index.php?author_name=$matches[1]&subpage=$matches[2]', 'top' );
        add_rewrite_rule( 'member/([a-zA-Z0-9_-]+)/mentioned/page/([0-9]+)/?$', 'index.php?paged=$matches[2]&author_name=$matches[1]&subpage=mentioned', 'top' );
        add_rewrite_rule( 'member/([a-zA-Z0-9_-]+)/written/page/([0-9]+)/?$', 'index.php?paged=$matches[2]&author_name=$matches[1]&subpage=written', 'top' );
    }
    add_filter( 'init', 'idf_rewrite_profile_pages', 1, 3 );

    I can already visit /page/2 if a user has written that amount of posts, which can be seen on my profile, see https://new.internationaldownhillfederation.org/member/berry-plasman/written/page/2/ but if I change written to mentioned it goes to my first mentioned page (I only have one), but in my opinion the paged doesn’t throw an error because I have written enough posts to be able to create paged pages.

    So I think, if a user has not written enough posts to page an author archive page, it fails…

    I am starting to think it is impossible.

    Thread Starter Beee

    (@beee)

    I think the authors need to be added to the query, but I can’t seem to do that…

    Thread Starter Beee

    (@beee)

    Well I can add them, but they’re not recognised (yet).

    Thread Starter Beee

    (@beee)

    I have given up on it… it takes me too much time to achieve, so I built a different solution. I now show 3 teasers per row instead of 2 which saves a lot of space and I can now easily fit 50 on a page.

    See https://new.internationaldownhillfederation.org/member/emily-pross/mentioned/

    I am going to look into lazy loading on a later stage. The launch is more important ?? Over 1 year work in it… Thanks for your time @keesiemeijer

Viewing 15 replies - 1 through 15 (of 26 total)
  • The topic ‘Create fake paged author pages when there are no posts’ is closed to new replies.