【背景】
之前已经实现了手动给google xml sitemap的额外页面中,添加了对应的html页面地址,使得生成的xml sitemap包含了对应的html静态页面:
【基本解决】让wordpress中的google xml sitemap生成的xml包含静态html网页
但是却没法实现自动扫描某路径及其下的所有的HTML静态页面(及其其他格式)。
这导致如果有很多页面,在别的某些路径下面,如果想要将这些页面添加到sitemap中,则需要手动一点点加,因为wordpress的网站的数据库中没有这些html链接。
手动加的话,效率太低,很不方便。
希望google xml sitemap插件,能够支持添加一个文件夹,然后其可以自动扫描其它的,所支持的类型的文件,包括html页面,pdf,txt文件等等把对应的链接加入到sitemap中。
注:当前google xml sitemap版本是 3.2.7
下面就记录具体的折腾过程:
【如何给wordpress插件google xml sitemap添加支持自动扫描文件夹下所有类型文件,并添加链接到sitemap中】
1.先是去参考
htdocs\wp-content\plugins\google-sitemap-generator\sitemap-ui.php
中的Additional pages部分,照葫芦画瓢,写出了Additional Path:
<?php $this->HtmlPrintBoxHeader('sm_pages',__('Additional Path', 'sitemap')); ?> <?php _e('Here you can specify folder/path/directory which should be included in the sitemap, but do not belong to your Blog/WordPress database.<br />','sitemap'); ?> <script type="text/javascript"> //<![CDATA[ <?php $freqVals = "'" . implode("','",array_keys($this->sg->_freqNames)). "'"; $freqNames = "'" . implode("','",array_values($this->sg->_freqNames)). "'"; ?> var changeFreqVals = new Array( <?php echo $freqVals; ?> ); var changeFreqNames= new Array( <?php echo $freqNames; ?> ); var priorities= new Array(0 <?php for($i=0.1; $i<1; $i+=0.1) { echo "," . number_format($i,1,".",""); } ?>); var pages = [ <?php if(count($this->sg->_pages)>0) { for($i=0; $i<count($this->sg->_pages); $i++) { $v=&$this->sg->_pages[$i]; if($i>0) echo ","; echo '{url:"' . $v->getUrl() . '", priority:' . number_format($v->getPriority(),1,".","") . ', changeFreq:"' . $v->getChangeFreq() . '", lastChanged:"' . ($v!=null && $v->getLastMod()>0?date("Y-m-d",$v->getLastMod()):"") . '"}'; } } ?> ]; //]]> </script> <script type="text/javascript" src="<?php echo $this->sg->GetPluginUrl(); ?>img/sitemap.js"></script> <table width="100%" cellpadding="3" cellspacing="3" id="sm_pageTable"> <tr> <th scope="col"><?php _e('URL to the Path','sitemap'); ?></th> <th scope="col"><?php _e('Priority','sitemap'); ?></th> <th scope="col"><?php _e('Change Frequency','sitemap'); ?></th> <th scope="col"><?php _e('#','sitemap'); ?></th> </tr> <?php if(count($this->sg->_pages)<=0) { ?> <tr> <td colspan="5" align="center"><?php _e('No pages defined.','sitemap') ?></td> </tr><?php } ?> </table> <a href="javascript:void(0);" onclick="sm_addPage();"><?php _e("Add new Path",'sitemap'); ?></a> <?php $this->HtmlPrintBoxFooter(); ?>
然后可以正常显示出来了:
2.但是发现一个问题,就是点击“Additional Path”,结果新添加的输入框,却跑到“附加页面”部分去了:
所以,先要解决此问题。
然后就是用SI建立了对应的google-sitemap-generator的源码的项目,方便查找函数和字符串。
然后就是一点点看代码了。
3. 先是HtmlPrintBoxHeader和HtmlPrintBoxFooter,其都可以在本文件sitemap-ui.php中找到。
就是画框而已。暂不关心。
4.然后是sm_pages,没找到其定义,然后才发现,原来是传入给HtmlPrintBoxHeader和HtmlPrintBoxFooter,然后在输出的html源码中可以看到对应的此部分的全部源码:
<div id="sm_pages" class="postbox"> <h3 class="hndle"><span>Additional Path</span></h3> <div class="inside"> Here you can specify folder/path/directory which should be included in the sitemap, but do not belong to your Blog/WordPress database.<br /> <script type="text/javascript"> //<![CDATA[ var changeFreqVals = new Array( 'always','hourly','daily','weekly','monthly','yearly','never' ); var changeFreqNames= new Array( '总是','每小时','每天','每周','每月','每月','从不' ); var priorities= new Array(0 ,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0); var pages = [ ]; //]]> </script> <script type="text/javascript" src="http://localhost/wp-content/plugins/google-sitemap-generator/img/sitemap.js"></script> <table width="100%" cellpadding="3" cellspacing="3" id="sm_pageTable"> <tr> <th scope="col">URL to the Path</th> <th scope="col">优先</th> <th scope="col">更改频率</th> <th scope="col">#</th> </tr> <tr> <td colspan="5" align="center">没有页面</td> </tr> </table> <a href="javascript:void(0);" onclick="sm_addPage();">Add new Path</a> </div> </div>
暂时不改动sm_pages,好像也没影响。
5.关于_e(‘xxx’,’sitemap’);,看了下,感觉应该是调用字符串翻译为对应的语言的文字的。
此处,可以暂时不管这部分。
6.后来是无意间看到:
<a href="javascript:void(0);" onclick="sm_addPage();"><?php _e("Add new Path",'sitemap'); ?></a>
所以很明显,点击按钮添加页面的话,就是去调用sm_addPage,但是找了半天没找到。
后来才是通过上面建的SI的项目,全局搜索到了,在
\google-sitemap-generator\img\sitemap.js
中:
function sm_addPage(url,priority,changeFreq,lastChanged)
其中会有:
var table = document.getElementById('sm_pageTable').getElementsByTagName('TBODY')[0];
即,获得html中的sm_pageTable,然后生成对应html源码。
所以就又回去找sm_pageTable,然后才发现,原来自己照葫芦画瓢弄出的Additional Path中的代码所生成的table中的代码:
<table width="100%" cellpadding="3" cellspacing="3" id="sm_pageTable">
是和Additional pages中的一样的,所以,生成的输入框,才弄到了Additional pages中。
所以,去修改代码。
7.经历了千辛万苦,添加和改动了N多代码:
(1)sitemap-ui.php中,增加了:
//Apply path changes from POST $this->sg->_paths=$this->sg->HtmlApplyPaths();
和
<?php $this->HtmlPrintBoxHeader('sm_paths',__('Additional Path', 'sitemap')); ?> <?php _e('Here you can specify folder/path/directory which should be included in the sitemap, but do not belong to your Blog/WordPress database.<br />','sitemap'); ?> <script type="text/javascript"> //<![CDATA[ var priorities= new Array(0 <?php for($i=0.1; $i<1; $i+=0.1) { echo "," . number_format($i,1,".",""); } ?>); var paths = [ <?php if(count($this->sg->_paths)>0) { for($i=0; $i<count($this->sg->_paths); $i++) { $v=&$this->sg->_paths[$i]; if($i>0) echo ","; echo '{url:"' . $v->getUrl() . '", priority:' . number_format($v->getPriority(),1,".","") . '"}'; } } ?> ]; //]]> </script> <script type="text/javascript" src="<?php echo $this->sg->GetPluginUrl(); ?>img/sitemap.js"></script> <table width="100%" cellpadding="3" cellspacing="3" id="sm_pathTable"> <tr> <th scope="col"><?php _e('URL to the Path','sitemap'); ?></th> <th scope="col"><?php _e('Priority','sitemap'); ?></th> <th scope="col"><?php _e('#','sitemap'); ?></th> </tr> <?php if(count($this->sg->_paths)<=0) { ?> <tr> <td colspan="3" align="center"><?php _e('No paths defined.','sitemap') ?></td> </tr><?php } ?> </table> <a href="javascript:void(0);" onclick="sm_addPath();"><?php _e("Add new Path",'sitemap'); ?></a> <?php $this->HtmlPrintBoxFooter(); ?>
和
<script type="text/javascript">if(typeof(sm_loadPaths)=='function') addLoadEvent(sm_loadPaths); </script>
(2)sitemap-core.php中添加了:
/** * Represents an item in the path list * @author Arne Brachhold * @package sitemap * @since 3.0 */ class GoogleSitemapGeneratorPath { /** * @var string $_url Sets the URL or the relative path to the blog dir of the path * @access private */ var $_url; /** * @var float $_priority Sets the priority of this path * @access private */ var $_priority; /** * @var int $_lastMod Sets the lastMod date as a UNIX timestamp. * @access private */ var $_lastMod; /** * Initialize a new path object * * @since 3.0 * @access public * @author Arne Brachhold * @param bool $enabled Should this path be included in thesitemap * @param string $url The URL or path of the file * @param float $priority The Priority of the path 0.0 to 1.0 * @param string $changeFreq The change frequency like daily, hourly, weekly * @param int $lastMod The last mod date as a unix timestamp */ function GoogleSitemapGeneratorPath($url="",$priority=0.0,$changeFreq="never",$lastMod=0) { $this->SetUrl($url); $this->SetProprity($priority); $this->SetChangeFreq($changeFreq); $this->SetLastMod($lastMod); } /** * Returns the URL of the path * * @return string The URL */ function GetUrl() { return $this->_url; } /** * Sets the URL of the path * * @param string $url The new URL */ function SetUrl($url) { $this->_url=(string) $url; } /** * Returns the priority of this path * * @return float the priority, from 0.0 to 1.0 */ function GetPriority() { return $this->_priority; } /** * Sets the priority of the path * * @param float $priority The new priority from 0.1 to 1.0 */ function SetProprity($priority) { $this->_priority=floatval($priority); } function Render() { if($this->_url == "/" || empty($this->_url)) return ''; $r=""; $r.= "\t<url>\n"; $r.= "\t\t<loc>" . $this->EscapeXML($this->_url) . "</loc>\n"; if($this->_lastMod>0) $r.= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00',$this->_lastMod) . "</lastmod>\n"; if(!empty($this->_changeFreq)) $r.= "\t\t<changefreq>" . $this->_changeFreq . "</changefreq>\n"; if($this->_priority!==false && $this->_priority!=="") $r.= "\t\t<priority>" . number_format($this->_priority,1) . "</priority>\n"; $r.= "\t</url>\n"; return $r; } function EscapeXML($string) { return str_replace ( array ( '&', '"', "'", '<', '>'), array ( '&' , '"', ''' , '<' , '>'), $string); } }//GoogleSitemapGeneratorPath
和
/** * Returns an array with GoogleSitemapGeneratorPath objects which is generated from POST values * * @since 3.0 * @see GoogleSitemapGeneratorPath * @access private * @author Arne Brachhold * @return array An array with GoogleSitemapGeneratorPath objects */ function HtmlApplyPaths() { // Array with all path URLs $paths_ur=(!isset($_POST["sm_paths_ur"]) || !is_array($_POST["sm_paths_ur"])?array():$_POST["sm_paths_ur"]); //Array with all priorities $paths_pr=(!isset($_POST["sm_paths_pr"]) || !is_array($_POST["sm_paths_pr"])?array():$_POST["sm_paths_pr"]); //Array where the new paths are stored $paths=array(); //Loop through all defined paths and set their properties into an object if(isset($_POST["sm_paths_mark"]) && is_array($_POST["sm_paths_mark"])) { for($i=0; $i<count($_POST["sm_paths_mark"]); $i++) { //Create new object $p=new GoogleSitemapGeneratorPath(); if(substr($paths_ur[$i],0,4)=="www.") $paths_ur[$i]="http://" . $paths_ur[$i]; $p->SetUrl($paths_ur[$i]); $p->SetProprity($paths_pr[$i]); //Add it to the array array_push($paths,$p); } } return $paths; }
(3)img\sitemap.js中添加了:
function sm_addPath(url,priority,changeFreq,lastChanged) { var table = document.getElementById('sm_pathTable').getElementsByTagName('TBODY')[0]; var ce = function(ele) { return document.createElement(ele) }; var tr = ce('TR'); var td = ce('TD'); var iUrl = ce('INPUT'); iUrl.type="text"; iUrl.style.width='95%'; iUrl.name="sm_paths_ur[]"; if(url) iUrl.value=url; td.appendChild(iUrl); tr.appendChild(td); td = ce('TD'); td.style.width='150px'; var iPrio = ce('SELECT'); iPrio.style.width='95%'; iPrio.name="sm_paths_pr[]"; for(var i=0; i <priorities.length; i++) { var op = ce('OPTION'); op.text = priorities[i]; op.value = priorities[i]; try { iPrio.add(op, null); // standards compliant; doesn't work in IE } catch(ex) { iPrio.add(op); // IE only } if(priority && priority == op.value) { iPrio.selectedIndex = i; } } td.appendChild(iPrio); tr.appendChild(td); var td = ce('TD'); td.style.textAlign="center"; td.style.width='5px'; var iAction = ce('A'); iAction.innerHTML = 'X'; iAction.href="javascript:void(0);" iAction.onclick = function() { table.removeChild(tr); }; td.appendChild(iAction); tr.appendChild(td); var mark = ce('INPUT'); mark.type="hidden"; mark.name="sm_paths_mark[]"; mark.value="true"; tr.appendChild(mark); var firstRow = table.getElementsByTagName('TR')[1]; if(firstRow) { var firstCol = (firstRow.childNodes[1]?firstRow.childNodes[1]:firstRow.childNodes[0]); if(firstCol.colSpan>1) { firstRow.parentNode.removeChild(firstRow); } } var cnt = table.getElementsByTagName('TR').length; if(cnt%2) tr.className="alternate"; table.appendChild(tr); }
和
function sm_loadPaths() { for(var i=0; i<paths.length; i++) { sm_addPath(paths[i].url,paths[i].priority,paths[i].changeFreq,paths[i].lastChanged); } }
这样,终于实现了,点击Add new Path,可以增加对应的输入框了:
接下来,就是看看,如何把所输入的地址和设置的优先级,然后传递到底层处理函数,然后检索该路径下面的所有的文件,过滤出支持的文件类型,生成文件链接,添加到sitemap中去了。
8.接着先去测试了一下:
就在上面输入框中输入了一个url path:
http://localhost/files/doc/docbook/
对应的,也去建立了对应的文件夹
files/doc/docbook/
并且在其下放了一些xml,html,txt等用来测试生成文件链接。
然后去点击“更新设置”:
最后出现错误:
Fatal error: Call to undefined method GoogleSitemapGeneratorPath::SetChangeFreq() in xxx\wp-content\plugins\google-sitemap-generator\sitemap-core.php on line 430
不过,此错误出现也是正常的,毕竟里面很多功能函数没实现呢。
接下来就是去搞懂google xml sitemap的内在添加additional pages的逻辑,然后照葫芦画瓢添加additional paths。
9.看了半天,终于大概搞懂了其内在大概逻辑了:
对于”附加页面“部分来说:
先是点击“增加一个新的页面”,执行:
sitemap-ui.php中的:
<a href="javascript:void(0);" onclick="sm_addPage();"><?php _e("Add new page",'sitemap'); ?></a>
中的sm_addPage,此函数在img\sitemap.js中:
function sm_addPage(url,priority,changeFreq,lastChanged) {
此负责生成对应输入框,其中还会生成对应的变量sm_pages_ur,sm_pages_pr,sm_pages_cf,sm_pages_lm,sm_pages_mark。
输入完对应的地址url后,点击“更新设置”,则会调用sitemap-ui.php中的
<input type="submit" name="sm_update" value="<?php _e('Update options', 'sitemap'); ?>" />
中的sm_update,其对应代码是在同一文件中的:
} else if (!empty($_POST['sm_update'])) { //Pressed Button: Update Config
该处代码的主要逻辑是:
A。通过:
foreach($this->sg->_options as $k=>$v) {
去处理每一个sg(sitemap generator)的参数选项(options)。
这些参数都在sitemap-core.php中的:
function InitOptions() {
中,包含几大类:
boolean类型的,都是以sm_b_开头的;
include某种东西的,都是以sm_in_开头的;
更改频率(change frequency)方面的,以sm_cf_开头;
优先级(priority)方面以sm_pr_开头;
其他信息(information)方面,以sm_i_开头。
上述变量处理完毕后,再调用:
$this->sg->_pages=$this->sg->HtmlApplyPages();
去处理之前在“附加页面(Additional Pages)”中新添加的每一个页面page,该函数在sitemap-core.php中:
function HtmlApplyPages() {
其会处理(之前sm_addPage所生成的)变量:sm_pages_ur,sm_pages_pr,sm_pages_cf,sm_pages_lm,sm_pages_mark,经过一番判断,如果最后修改时间是更新的,则最后通过:
array_push($pages,$p);
添加到对应的变量pages中去。
而此pages变量,是同文件中,class GoogleSitemapGenerator中的一个成员变量:
class GoogleSitemapGenerator { ...... /** * @var array The saved additional pages */ var $_pages = array();
接下来,再调用
$this->sg->SaveOptions()
存储当前插件的所有配置,
再调用
$this->sg->SavePages()
去存储(上面的那个pages所包含的)页面。
对应的SavePages,也在sitemap-core.php中:
function SavePages() {
其通过
get_option("sm_cpages");
获得之前的保存的旧的pages,然后比较,如果有变动,用
delete_option("sm_cpages");
删除旧的,再用
add_option("sm_cpages",$this->_pages,null,"no");
添加当前新的pages。
与此相关的,SavePages函数上面,有个LoadPages函数,其是在sitemap-ui.php中的:
<script type="text/javascript">if(typeof(sm_loadPages)=='function') addLoadEvent(sm_loadPages); </script>
是在最开始的时候页面载入的时候调用的。
该函数中,是通过:
$pagesString=$wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name = 'sm_cpages'");
去获得之前所保存的,用户所设置的额外页面的数据的。
至此,可以看出,是将这些额外页面的数据,保存到MySQL数据库中的,然后通过SELECT语句去读出来的。
然后大概看了下代码,其中add_option,是针对sm_cpages操作的。
而此处的option,从LoadPages可以看出是$wpdb->options。而$wpdb,则是wordpress的database,应该是会有对应机制会去保存更新此数据的,所以暂不关心。
10.接下来,很明显,就是去实现对应的HtmlApplyPaths,保存添加的路径,找到每个路径下面的所有文件,然后添加每个page到pages变量中,即可。
11.经过折腾,已经实现了,将每个path所生成的其下的page地址,都加到原先的pages里面了。
12.想要先实现,将path可以添加到“Additional Paths”,然后保存配置后,path也可以显示出来。
然后相关的代码,经过整理后,很快基本弄好了,但是却发现,手动输入的path后,保存配置后,却无法显示出来,接下来,就是漫长的调试,期间,通过添加php的echo打印,发现输入的path,数据库中也有用了保存了,但是还是无法显示出来。最后的最后,发现,原来是,在sitemap-ui.php中,最开始参考:
var pages = [ <?php if(count($this->sg->_pages)>0) { for($i=0; $i<count($this->sg->_pages); $i++) { $v=&$this->sg->_pages[$i]; if($i>0) echo ","; echo '{url:"' . $v->getUrl() . '", priority:' . number_format($v->getPriority(),1,".","") . ', changeFreq:"' . $v->getChangeFreq() . '", lastChanged:"' . ($v!=null && $v->getLastMod()>0?date("Y-m-d",$v->getLastMod()):"") . '"}'; } } ?> ];
所照葫芦画瓢写出来的:
var paths = [ <?php if(count($this->sg->_paths)>0) { for($i=0; $i<count($this->sg->_paths); $i++) { $v=&$this->sg->_paths[$i]; if($i>0) echo ","; echo '{url:"' . $v->getUrl() . '", priority:' . number_format($v->getPriority(),1,".","") . '"}'; } } ?> ];
会生成出来这样的html代码:
var paths = [ {url:"path1111", priority:0.0"} ];
而参考原先正常的输出:
var pages = [ {url:"page111111", priority:0.0, changeFreq:"always", lastChanged:""},{url:"page22222", priority:0.0, changeFreq:"always", lastChanged:""} ];
很明显,多了个双引号,所以,把上述上述双引号去掉,即可。
此时,就可以正常保存所输入的path,并显示出来了。
13.接下来,就是完善整个功能了。
14.调试代码的期间,遇到很多HTML,Javascript等方面的问题,折腾了N个小时,最后基本都解决了。
相关的经验和教训,参见:
15.最后终于搞定了,实现自己所需要的功能了,即:
给定一个路径,可以生成该路径下面的,指定文件类型的各个文件的url
这样,google xml sitemap就可以把这些文件的url添加到所生成的sitemap的xml文件中去了。
就免去手动一个个输入,这么麻烦了。
16.然后又去下载了Poedit工具,然后用Poedit将本地的,添加了对应的翻译,的po文件:
plugin\google-sitemap-generator\lang\sitemap-zh_CN.po
转换为对应的:
plugin\google-sitemap-generator\lang\sitemap-zh_CN.mo
如此,就可以实现正常显示中文了。
所有一切就绪,然后上传到自己的网站上,试了下,可以生成所需要的路径:
然后把整个对应的修改后的google-sitemap-generator上传到这里:
google-sitemap-generator_addAddtionalPaths_2012-07-03.7z
供需要的下载。
转载请注明:在路上 » 【已完全解决】折腾给WordPress Google XML Sitemap中添加支持子目录自动扫描功能,包含HTML静态页面等可识别的格式