In the article details page, we often add the previous article, the next article display. Why add the presentation of the previous post and the next post?

On the one hand, the user to see the end, we usually think that he is interested in the article compares, more convenient for users to view more related articles, this time we will be associated with this article has certain demonstrated in the previous, next, convenient user click through to the corresponding view the article, to a certain extent reduce the user’s bounce rate.

On the other hand, it is convenient for search engines to grab more page links and achieve better content collection. If each article is isolated, spiders can only rely on the home page or list page to grab the content, which will make some links difficult for spiders to find, and thus cannot be indexed by search engines. Adding previous and next articles to the article details page increases the exposure of the article content links and increases the likelihood of spiders crawling.

The HTML code of the previous and the next article

<div class="layui-card">
    <div class="layui-card-body">
        <div class="article-prev-next">
            {% if prev %}
            <li class="article-prev">The last:<a href="/article/{{prev.Id}}">{{prev.Title}}</a></li>
            {% endif %}
            {% if next %}
            <li class="article-next">Next up:<a href="/article/{{next.Id}}">{{next.Title}}</a></li>
            {% endif %}
        </div>
    </div>
</div>
Copy the code

HTML code is quite simple, is to determine whether there is a previous article, if there is, output. The same goes for the next one. In fact, we can also do a little more detailed here, for example, if there is no previous or next chapter, then give a hint and say no. Such as:

<li class="article-prev">The last:{% if prev %}
    <a href="/article/{{prev.Id}}">{{prev.Title}}</a>
  {% else %}Without the{% endif %}
</li>
<li class="article-next">Next up:{% if next %}
    <a href="/article/{{next.Id}}">{{next.Title}}</a>
  {% else %}Without the{% endif %}
</li>
Copy the code

When there is no previous post or next post, it will show that there is no previous post or next post, but the previous post or next post will always occupy placeholders to ensure page integrity.

The controller code from the previous and next articles

In the article details controller controller/article. Go, we add the previous and next article codes and bind them to the view:

	// Get the previous post
	prev, _ := provider.GetPrevArticleById(article.CategoryId, id)
	// Get the next article
	next, _ := provider.GetNextArticleById(article.CategoryId, id)
Copy the code

We respectively using the provider. GetPrevArticleById (), the provider. GetPrevArticleById () to obtain the handover. They all need to obtain the next and next articles according to the classification ID and article ID of the article. The specific logic is different, which will be introduced in detail below.

The concrete logic realization of the upper and lower chapters

We in the provider/article. Go, increased the provider GetPrevArticleById (), the provider. GetPrevArticleById () two functions:

func GetPrevArticleById(categoryId uint, id uint) (*model.Article, error) {
	var article model.Article
	db := config.DB
	if err := db.Model(model.Article{}).Where("`category_id` = ?", categoryId).Where("`id` < ?", id).Where("`status` = 1").Last(&article).Error; err ! =nil {
		return nil, err
	}

	return &article, nil
}

func GetNextArticleById(categoryId uint, id uint) (*model.Article, error) {
	var article model.Article
	db := config.DB
	if err := db.Model(model.Article{}).Where("`category_id` = ?", categoryId).Where("`id` > ?", id).Where("`status` = 1").First(&article).Error; err ! =nil {
		return nil, err
	}

	return &article, nil
}
Copy the code

The previous and the next get code, roughly the same. Handover to obtain the article, we are all restricted to the classification of the article, that is to say, the article, as shown in handover is only belongs to the classification of the current article, will display in the handover, the aim is to reduce the has nothing to do with the display of the article, such as my blog have the technology to share, the classification of the beer and entertainment, The articles they contain are completely unrelated, and by showing them side by side, it is likely that the user browsing the article will not click on the corresponding article link. It was a failure in terms of showing it to the user.

Where(“id

Since the previous post and the next post, for the post itself, are reversed, in the previous post we used a judgment ID that is less than the current post ID, so in the next post our judgment id is greater than the current post ID. For the next article, we use gorM’s First() method. With this method, GORM automatically adds the id ASC sort and returns the First data, ensuring that the next article returned is the one whose ID is larger than the current article and is closest to the current article.

For example, if the data volume of the article table is very large, it may be judged by id greater than or less than the result set of the current article too much, resulting in mysql query too slow and affecting the page performance. For example, if the current ID is 10 and there are 1,000,000 articles in the whole table, then the last article will have only 1-9 ids at most, and the next article will have close to 1,000,000 ids. In this case, the results will be significantly affected. So here we try to add id qualifiers. For example, assuming the limit ID is the id of the current id extension 1000, we could write:

/ / a
.Where("id BETWEEN ? AND ?", id- 1000., id - 1)
/ / the next article
.Where("id BETWEEN ? AND ?", id+1, id + 1000)
Copy the code

We can also use greater than or less than between to judge that they are equivalent:

/ / a
.Where("id < ? AND id >= ?", id, id - 1000.)
/ / the next article
.Where("id > ? AND id <= ?", id, id + 1000)
Copy the code

The full statement is:

func GetPrevArticleById(categoryId uint, id uint) (*model.Article, error) {
	var article model.Article
	db := config.DB
	if err := db.Model(model.Article{}).Where("`category_id` = ?", categoryId).Where("id BETWEEN ? AND ?", id- 1000., id - 1).Where("`status` = 1").Last(&article).Error; err ! =nil {
		return nil, err
	}

	return &article, nil
}

func GetNextArticleById(categoryId uint, id uint) (*model.Article, error) {
	var article model.Article
	db := config.DB
	if err := db.Model(model.Article{}).Where("`category_id` = ?", categoryId).Where("id BETWEEN ? AND ?", id+1, id + 1000).Where("`status` = 1").First(&article).Error; err ! =nil {
		return nil, err
	}

	return &article, nil
}
Copy the code

In addition to limited scope optimization, in order to improve the relevance of the upper and lower articles, if there are other conditions in our articles, they can also be added, such as they belong to the same label, the same topic, etc.

The complete project sample code is hosted on GitHub. The complete project code can be viewed at github.com/fesiong/gob… You can also fork a copy to make changes on it.