{"id":197,"date":"2026-09-05T15:31:59","date_gmt":"2026-09-05T15:31:59","guid":{"rendered":"https:\/\/enigma.ng\/blog\/?p=197"},"modified":"2026-09-05T18:35:09","modified_gmt":"2026-09-05T18:35:09","slug":"maximizing-search-engine-crawl-budget-on-your-mybb-forum","status":"publish","type":"post","link":"https:\/\/enigma.ng\/blog\/maximizing-search-engine-crawl-budget-on-your-mybb-forum\/","title":{"rendered":"Maximizing Search Engine Crawl Budget On Your MYBB Forum"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">From my experience as a MYBB Big Board Owner, I&#8217;ll tell you that the bigger your forum gets, the more you need to maximise your crawl budget. While plugins like <strong>Google SEO (Updated for PHP 8)<\/strong> prevent duplicate content issues, you still have to worry about your crawl budget.<br>Your headaches are the:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Post pages<\/li>\n\n\n\n<li>Archive pages<\/li>\n\n\n\n<li>Print Thread pages<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">You could have only a few threads or posts yet so many URLs pointing to these few content. MYBB&#8217;s URL structure needs to be revisited in my opinion. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">LLMs and Search engines love your archive and print thread pages because they&#8217;re lightweight and text rich. The problem begins when they start indexing\/referencing these pages instead of the full versions (where your structure, ads or tracking scripts reside). If you&#8217;re cool with training LLMs without maximizing visits then you could leave these pages, else, now is a good time to properly redirect these pages.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Managing the Hovatek Forum<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/www.hovatek.com\/forum\/\">Hovatek Forum<\/a> has been running since 2012, and on MYBB. I&#8217;d started off as forum.hovatek.com but later switched to hovatek.com\/forum (I&#8217;ll talk about my reasons in a future post). Here are some things I put in place to reduce the multiple URLs generated by MYBB.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Modifying postbit_url template<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">I modified the <strong>href<\/strong> attribute at Post Bit Templates &gt; postbit_posturl template from:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>href=\"{$post&#91;'postlink']}#pid{$post&#91;'pid']}\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>href=\"#pid{$post&#91;'pid']}\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Adding Htacess rules<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">I added the following htaccess rules to redirect the print thread and archive pages to their corresponding full versions<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Redirect printthread\n&lt;IfModule mod_rewrite.c&gt;\nRewriteEngine On\n\n# \/printthread.php?tid=N&amp;page=P to \/forum\/thread-N-page-P.html\nRewriteCond %{QUERY_STRING} ^tid=(&#91;0-9]+)&amp;page=(&#91;0-9]+)$\nRewriteRule ^printthread\\.php$ \/forum\/thread-%1-page-%2.html? &#91;R=301,L]\n\n# \/printthread.php?tid=N to \/forum\/thread-N.html\nRewriteCond %{QUERY_STRING} ^tid=(&#91;0-9]+)$\nRewriteRule ^printthread\\.php$ \/forum\/thread-%1.html? &#91;R=301,L]\n\n# \/archive\/index.php -&gt; \/forum\/index.php\nRewriteCond %{QUERY_STRING} ^$\nRewriteRule ^archive\/index\\.php$ \/forum\/index.php &#91;R=301,L]\n\n# \/archive\/index.php?forum-N.html -&gt; \/forum\/forum-N.html\nRewriteCond %{QUERY_STRING} ^forum-(&#91;0-9]+)\\.html$\nRewriteRule ^archive\/index\\.php$ \/forum\/forum-%1.html? &#91;R=301,L]\n\n# \/archive\/index.php?forum-N-P.html -&gt; \/forum\/forum-N-page-P.html\nRewriteCond %{QUERY_STRING} ^forum-(&#91;0-9]+)-(&#91;0-9]+)\\.html$\nRewriteRule ^archive\/index\\.php$ \/forum\/forum-%1-page-%2.html &#91;R=301,L]\n\n# \/archive\/index.php?thread-N.html -&gt; \/forum\/thread-N.html\nRewriteCond %{QUERY_STRING} ^thread-(&#91;0-9]+)\\.html$\nRewriteRule ^archive\/index\\.php$ \/forum\/thread-%1.html &#91;R=301,L]\n\n# \/archive\/index.php?thread-N-P.html -&gt; \/forum\/thread-N-page-P.html\nRewriteCond %{QUERY_STRING} ^thread-(&#91;0-9]+)-(&#91;0-9]+)\\.html$\nRewriteRule ^archive\/index\\.php$ \/forum\/thread-%1-page-%2.html &#91;R=301,L]\n\n# \/archive\/index.php\/thread-N.html -&gt; \/forum\/thread-N.html\nRewriteRule ^archive\/index\\.php\/thread-(&#91;0-9]+)\\.html$ \/forum\/thread-$1.html &#91;R=301,L]\n\n# \/archive\/index.php\/thread-N-P.html -&gt; \/forum\/thread-N-page-P.html\nRewriteRule ^archive\/index\\.php\/thread-(&#91;0-9]+)-(&#91;0-9]+)\\.html$ \/forum\/thread-$1-page-$2.html &#91;R=301,L]\n\n&lt;\/IfModule&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a redirect plugin<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">I created a plugin to redirect -post URLs to their corresponding -page URLs. The plugin gets the post ID (if specified) then enumerates the thread ID (if unspecified). It then queries the database for visible (to the user) posts in the given thread before the post ID and splits the count by the number of threads per page; thereby calculating the page where the post belongs.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n$plugins-&gt;add_hook(\"showthread_start\", \"redirect_thread_run\");\n\/\/ Disallow direct access to this file for security reasons\nif (!defined(\"IN_MYBB\")) {\n\tdie(\"Direct initialization of this file is not allowed.\");\n}\n\n\n\n\nfunction redirect_post_urls_info()\n{\n\treturn array(\n\t\t\"name\"\t\t\t=&gt; \"Redirect Post URLs\",\n\t\t\"description\"\t=&gt; \"Redirect -post urls to -page\",\n\t\t\"website\"\t\t=&gt; \"https:\/\/www.hovatek.com\",\n\t\t\"author\"\t\t=&gt; \"Team Hovatek\",\n\t\t\"authorsite\"\t=&gt; \"https:\/\/www.hovatek.com\",\n\t\t\"version\"\t\t=&gt; \"1.1\",\n\t\t\"compatibility\" =&gt; \"*\"\n\t);\n}\n\nfunction myplugin_install() {}\n\nfunction myplugin_is_installed() {}\n\nfunction myplugin_uninstall() {}\n\nfunction myplugin_activate() {}\n\nfunction myplugin_deactivate() {}\n\nfunction redirect_thread_run()\n{\n\n\tglobal $db, $mybb;\n\n\t\/\/ If there is a pid\n\tif (!empty($mybb-&gt;input&#91;'pid'])) {\n\n\t\t\/\/ Set here to fetch only approved\/deleted posts (and then below for a moderator we change this).\n\t\t$visible_states = array(\"1\");\n\t\t$visible_condition = \"visible IN (\" . implode(',', array_unique($visible_states)) . \")\";\n\n\t\t\/\/ Allow viewing own unapproved threads for logged in users\n\t\tif ($mybb-&gt;user&#91;'uid'] &amp;&amp; $mybb-&gt;settings&#91;'showownunapproved']) {\n\t\t\t$own_unapproved = ' AND (%1$s' . $visible_condition . ' OR (%1$svisible=0 AND %1$suid=' . (int)$mybb-&gt;user&#91;'uid'] . '))';\n\t\t\t$visibleonly_p = sprintf($own_unapproved, 'p.');\n\t\t} else {\n\t\t\t$visibleonly_p = \" AND p.\" . $visible_condition;\n\t\t}\n\n\t\t\/\/ If there is no tid but a pid, trick the system into thinking there was a tid anyway.\n\t\tif (!isset($mybb-&gt;input&#91;'tid'])) {\n\t\t\t\/\/ see if we already have the post information\n\t\t\tif (isset($style) &amp;&amp; $style&#91;'pid'] == $mybb-&gt;get_input('pid', MyBB::INPUT_INT) &amp;&amp; $style&#91;'tid']) {\n\t\t\t\t$mybb-&gt;input&#91;'tid'] = $style&#91;'tid'];\n\t\t\t} else {\n\t\t\t\t$options = array(\n\t\t\t\t\t\"limit\" =&gt; 1\n\t\t\t\t);\n\t\t\t\t$query = $db-&gt;simple_select(\"posts\", \"fid,tid,visible\", \"pid=\" . $mybb-&gt;get_input('pid', MyBB::INPUT_INT), $options);\n\t\t\t\t$post = $db-&gt;fetch_array($query);\n\n\t\t\t\tif (\n\t\t\t\t\tempty($post) ||\n\t\t\t\t\t(\n\t\t\t\t\t\t$post&#91;'visible'] == 0 &amp;&amp; !(\n\t\t\t\t\t\t\tis_moderator($post&#91;'fid'], 'canviewunapprove') ||\n\t\t\t\t\t\t\t($mybb-&gt;user&#91;'uid'] &amp;&amp; $post&#91;'uid'] == $mybb-&gt;user&#91;'uid'] &amp;&amp; $mybb-&gt;settings&#91;'showownunapproved'])\n\t\t\t\t\t\t)\n\t\t\t\t\t) ||\n\t\t\t\t\t($post&#91;'visible'] == -1 &amp;&amp; !is_moderator($post&#91;'fid'], 'canviewdeleted'))\n\t\t\t\t) {\n\t\t\t\t\t\/\/ post does not exist --&gt; show corresponding error\n\t\t\t\t\terror($lang-&gt;error_invalidpost);\n\t\t\t\t}\n\n\t\t\t\t$mybb-&gt;input&#91;'tid'] = $post&#91;'tid'];\n\t\t\t}\n\t\t}\n\n\t\t\/\/ Assuming $pid and $tid (thread id) are already known\/set\n\t\t$pid = (int)$mybb-&gt;input&#91;'pid'];\n\t\t$tid = (int)$mybb-&gt;input&#91;'tid'];\n\n\t\t\/\/ Get posts per page setting\n\t\t$perpage = $mybb-&gt;settings&#91;'postsperpage'];\n\t\tif (!$perpage) {\n\t\t\t$perpage = 10; \/\/ fallback default\n\t\t}\n\n\n\n\t\t\/\/ Count how many posts come before this specific post in the same thread\n\t\t$query = $db-&gt;query(\"\n        SELECT COUNT(p.dateline) AS count \n        FROM \" . TABLE_PREFIX . \"posts p \n        WHERE p.tid = '\" . $tid . \"' \n          AND p.dateline &lt;= (SELECT dateline FROM \" . TABLE_PREFIX . \"posts WHERE pid = '$pid')\n          {$visibleonly_p}\n    \");\n\n\n\t\t$result = $db-&gt;fetch_field($query, \"count\");\n\t\t$page = ceil($result \/ $perpage);\n\t\t$thread_url = $page &gt; 1 ? \"thread-\" . $tid . \"-page-\" . $page : \"thread-\" . $tid;\n\n\t\t\/\/ Redirect -post to -page with 301\n\t\theader(\"Location: {$mybb-&gt;settings&#91;'bburl']}\/{$thread_url}.html#pid{$pid}\", true, 301);\n\t}\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>From my experience as a MYBB Big Board Owner, I&#8217;ll tell you that the bigger your forum gets, the more you need to maximise your crawl budget. While plugins like Google SEO (Updated for PHP 8) prevent duplicate content issues, you still have to worry about your crawl budget.Your headaches are the: You could have [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":199,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[6],"tags":[31,30],"class_list":["post-197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-software-development","tag-forum","tag-mybb"],"_links":{"self":[{"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/posts\/197","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/comments?post=197"}],"version-history":[{"count":5,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/posts\/197\/revisions"}],"predecessor-version":[{"id":204,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/posts\/197\/revisions\/204"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/media\/199"}],"wp:attachment":[{"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/media?parent=197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/categories?post=197"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/enigma.ng\/blog\/wp-json\/wp\/v2\/tags?post=197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}