qa-xml-sitemap.php 7.45 KB
Newer Older
Scott committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-plugin/xml-sitemap/qa-xml-sitemap.php
	Description: Page module class for XML sitemap plugin


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

Scott committed
23 24 25 26 27 28 29 30 31 32 33 34
class qa_xml_sitemap
{
	public function option_default($option)
	{
		switch ($option) {
			case 'xml_sitemap_show_questions':
			case 'xml_sitemap_show_users':
			case 'xml_sitemap_show_tag_qs':
			case 'xml_sitemap_show_category_qs':
			case 'xml_sitemap_show_categories':
				return true;
				break;
Scott committed
35
		}
Scott committed
36
	}
Scott committed
37 38


Scott committed
39 40
	public function admin_form()
	{
Scott committed
41
		require_once QA_INCLUDE_DIR.'util/sort.php';
Scott committed
42

Scott committed
43
		$saved=false;
Scott committed
44

Scott committed
45 46
		if (qa_clicked('xml_sitemap_save_button')) {
			qa_opt('xml_sitemap_show_questions', (int)qa_post_text('xml_sitemap_show_questions_field'));
Scott committed
47

Scott committed
48 49
			if (!QA_FINAL_EXTERNAL_USERS)
				qa_opt('xml_sitemap_show_users', (int)qa_post_text('xml_sitemap_show_users_field'));
Scott committed
50

Scott committed
51 52
			if (qa_using_tags())
				qa_opt('xml_sitemap_show_tag_qs', (int)qa_post_text('xml_sitemap_show_tag_qs_field'));
Scott committed
53

Scott committed
54 55 56
			if (qa_using_categories()) {
				qa_opt('xml_sitemap_show_category_qs', (int)qa_post_text('xml_sitemap_show_category_qs_field'));
				qa_opt('xml_sitemap_show_categories', (int)qa_post_text('xml_sitemap_show_categories_field'));
Scott committed
57 58
			}

Scott committed
59 60 61 62 63
			$saved=true;
		}

		$form=array(
			'ok' => $saved ? 'XML sitemap settings saved' : null,
Scott committed
64

Scott committed
65 66 67 68 69 70
			'fields' => array(
				'questions' => array(
					'label' => 'Include question pages',
					'type' => 'checkbox',
					'value' => (int)qa_opt('xml_sitemap_show_questions'),
					'tags' => 'name="xml_sitemap_show_questions_field"',
Scott committed
71
				),
Scott committed
72
			),
Scott committed
73

Scott committed
74 75 76 77
			'buttons' => array(
				array(
					'label' => 'Save Changes',
					'tags' => 'name="xml_sitemap_save_button"',
Scott committed
78
				),
Scott committed
79 80 81 82 83 84 85 86 87
			),
		);

		if (!QA_FINAL_EXTERNAL_USERS)
			$form['fields']['users']=array(
				'label' => 'Include user pages',
				'type' => 'checkbox',
				'value' => (int)qa_opt('xml_sitemap_show_users'),
				'tags' => 'name="xml_sitemap_show_users_field"',
Scott committed
88 89
			);

Scott committed
90 91 92 93 94 95 96
		if (qa_using_tags())
			$form['fields']['tagqs']=array(
				'label' => 'Include question list for each tag',
				'type' => 'checkbox',
				'value' => (int)qa_opt('xml_sitemap_show_tag_qs'),
				'tags' => 'name="xml_sitemap_show_tag_qs_field"',
			);
Scott committed
97

Scott committed
98 99 100 101 102 103 104
		if (qa_using_categories()) {
			$form['fields']['categoryqs']=array(
				'label' => 'Include question list for each category',
				'type' => 'checkbox',
				'value' => (int)qa_opt('xml_sitemap_show_category_qs'),
				'tags' => 'name="xml_sitemap_show_category_qs_field"',
			);
Scott committed
105

Scott committed
106 107 108 109 110 111
			$form['fields']['categories']=array(
				'label' => 'Include category browser',
				'type' => 'checkbox',
				'value' => (int)qa_opt('xml_sitemap_show_categories'),
				'tags' => 'name="xml_sitemap_show_categories_field"',
			);
Scott committed
112 113
		}

Scott committed
114 115
		return $form;
	}
Scott committed
116 117


Scott committed
118 119 120 121 122 123 124 125 126 127
	public function suggest_requests()
	{
		return array(
			array(
				'title' => 'XML Sitemap',
				'request' => 'sitemap.xml',
				'nav' => null, // 'M'=main, 'F'=footer, 'B'=before main, 'O'=opposite main, null=none
			),
		);
	}
Scott committed
128 129


Scott committed
130 131 132 133
	public function match_request($request)
	{
		return ($request=='sitemap.xml');
	}
Scott committed
134 135


Scott committed
136 137 138
	public function process_request($request)
	{
		@ini_set('display_errors', 0); // we don't want to show PHP errors inside XML
Scott committed
139

Scott committed
140
		header('Content-type: text/xml; charset=utf-8');
Scott committed
141

Scott committed
142 143
		echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
		echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'."\n";
Scott committed
144 145


Scott committed
146
	//	Question pages
Scott committed
147

Scott committed
148 149 150 151
		if (qa_opt('xml_sitemap_show_questions')) {
			$hotstats=qa_db_read_one_assoc(qa_db_query_sub(
				"SELECT MIN(hotness) AS base, MAX(hotness)-MIN(hotness) AS spread FROM ^posts WHERE type='Q'"
			));
Scott committed
152

Scott committed
153
			$nextpostid=0;
Scott committed
154

Scott committed
155 156 157 158 159
			while (1) {
				$questions=qa_db_read_all_assoc(qa_db_query_sub(
					"SELECT postid, title, hotness FROM ^posts WHERE postid>=# AND type='Q' ORDER BY postid LIMIT 100",
					$nextpostid
				));
Scott committed
160

Scott committed
161 162 163 164 165 166 167
				if (!count($questions))
					break;

				foreach ($questions as $question) {
					$this->sitemap_output(qa_q_request($question['postid'], $question['title']),
						0.1+0.9*($question['hotness']-$hotstats['base'])/(1+$hotstats['spread']));
					$nextpostid=max($nextpostid, $question['postid']+1);
Scott committed
168 169
				}
			}
Scott committed
170
		}
Scott committed
171 172


Scott committed
173
	//	User pages
Scott committed
174

Scott committed
175 176
		if ((!QA_FINAL_EXTERNAL_USERS) && qa_opt('xml_sitemap_show_users')) {
			$nextuserid=0;
Scott committed
177

Scott committed
178 179 180 181 182
			while (1) {
				$users=qa_db_read_all_assoc(qa_db_query_sub(
					"SELECT userid, handle FROM ^users WHERE userid>=# ORDER BY userid LIMIT 100",
					$nextuserid
				));
Scott committed
183

Scott committed
184 185
				if (!count($users))
					break;
Scott committed
186

Scott committed
187 188 189
				foreach ($users as $user) {
					$this->sitemap_output('user/'.$user['handle'], 0.25);
					$nextuserid=max($nextuserid, $user['userid']+1);
Scott committed
190 191
				}
			}
Scott committed
192
		}
Scott committed
193 194


Scott committed
195
	//	Tag pages
Scott committed
196

Scott committed
197 198
		if (qa_using_tags() && qa_opt('xml_sitemap_show_tag_qs')) {
			$nextwordid=0;
Scott committed
199

Scott committed
200 201 202 203 204
			while (1) {
				$tagwords=qa_db_read_all_assoc(qa_db_query_sub(
					"SELECT wordid, word, tagcount FROM ^words WHERE wordid>=# AND tagcount>0 ORDER BY wordid LIMIT 100",
					$nextwordid
				));
Scott committed
205

Scott committed
206 207
				if (!count($tagwords))
					break;
Scott committed
208

Scott committed
209 210 211
				foreach ($tagwords as $tagword) {
					$this->sitemap_output('tag/'.$tagword['word'], 0.5/(1+(1/$tagword['tagcount']))); // priority between 0.25 and 0.5 depending on tag frequency
					$nextwordid=max($nextwordid, $tagword['wordid']+1);
Scott committed
212 213
				}
			}
Scott committed
214
		}
Scott committed
215 216


Scott committed
217
	//	Question list for each category
Scott committed
218

Scott committed
219 220
		if (qa_using_categories() && qa_opt('xml_sitemap_show_category_qs')) {
			$nextcategoryid=0;
Scott committed
221

Scott committed
222 223 224 225 226
			while (1) {
				$categories=qa_db_read_all_assoc(qa_db_query_sub(
					"SELECT categoryid, backpath FROM ^categories WHERE categoryid>=# AND qcount>0 ORDER BY categoryid LIMIT 2",
					$nextcategoryid
				));
Scott committed
227

Scott committed
228 229
				if (!count($categories))
					break;
Scott committed
230

Scott committed
231 232 233
				foreach ($categories as $category) {
					$this->sitemap_output('questions/'.implode('/', array_reverse(explode('/', $category['backpath']))), 0.5);
					$nextcategoryid=max($nextcategoryid, $category['categoryid']+1);
Scott committed
234 235
				}
			}
Scott committed
236
		}
Scott committed
237 238


Scott committed
239
	//	Pages in category browser
Scott committed
240

Scott committed
241 242
		if (qa_using_categories() && qa_opt('xml_sitemap_show_categories')) {
			$this->sitemap_output('categories', 0.5);
Scott committed
243

Scott committed
244
			$nextcategoryid=0;
Scott committed
245

Scott committed
246 247 248 249 250 251
			while (1) { // only find categories with a child
				$categories=qa_db_read_all_assoc(qa_db_query_sub(
					"SELECT parent.categoryid, parent.backpath FROM ^categories AS parent ".
					"JOIN ^categories AS child ON child.parentid=parent.categoryid WHERE parent.categoryid>=# GROUP BY parent.categoryid LIMIT 100",
					$nextcategoryid
				));
Scott committed
252

Scott committed
253 254
				if (!count($categories))
					break;
Scott committed
255

Scott committed
256 257 258
				foreach ($categories as $category) {
					$this->sitemap_output('categories/'.implode('/', array_reverse(explode('/', $category['backpath']))), 0.5);
					$nextcategoryid=max($nextcategoryid, $category['categoryid']+1);
Scott committed
259 260 261 262
				}
			}
		}

Scott committed
263 264 265
		echo "</urlset>\n";

		return null;
Scott committed
266 267 268
	}


269 270 271 272 273
	/**
	 * @deprecated This function will become private in Q2A 1.8. It is specific to this plugin and
	 * should not be used by outside code.
	 */
	public function sitemap_output($request, $priority)
Scott committed
274 275 276 277 278 279 280
	{
		echo "\t<url>\n".
			"\t\t<loc>".qa_xml(qa_path($request, null, qa_opt('site_url')))."</loc>\n".
			"\t\t<priority>".max(0, min(1.0, $priority))."</priority>\n".
			"\t</url>\n";
	}
}