最新消息:VPS服务器又从fzhost.net换回Linode了,主题仍用朋友推荐的大前端D8

【已完全解决】折腾给WordPress Google XML Sitemap中添加支持子目录自动扫描功能,包含HTML静态页面等可识别的格式

WordPress crifan 1319浏览 0评论

【背景】

之前已经实现了手动给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(); ?>

然后可以正常显示出来了:

can show additional path

2.但是发现一个问题,就是点击“Additional Path”,结果新添加的输入框,却跑到“附加页面”部分去了:

add input goto additional page

所以,先要解决此问题。

然后就是用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 ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;'), $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,可以增加对应的输入框了:

can click to add input box

接下来,就是看看,如何把所输入的地址和设置的优先级,然后传递到底层处理函数,然后检索该路径下面的所有的文件,过滤出支持的文件类型,生成文件链接,添加到sitemap中去了。

8.接着先去测试了一下:

就在上面输入框中输入了一个url path:

http://localhost/files/doc/docbook/

对应的,也去建立了对应的文件夹

files/doc/docbook/

并且在其下放了一些xml,html,txt等用来测试生成文件链接。

然后去点击“更新设置”:

update config

最后出现错误:

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个小时,最后基本都解决了。

相关的经验和教训,参见:

HTML经验教训

Javascript经验教训

 

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静态页面等可识别的格式

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (2)

  1. 赞!不过其实你不觉得,直接修改WP代码太多地方的话,升级会很不方便么?以前我倾向于少使用插件,通过修改代码来实现。不过现在不怎么折腾了,直接上插件,要是没有插件再来改代码,这样升级起来就省事多了。
    Neverland Zhang6年前 (2012-08-03)回复
    • 用插件和该代码,各有优劣。不过单独讨论sitemap包含html页面的话,还真的必须用插件,因为如果不用,手动添加的话,要添加1000+的链接,会死人的。所以必须用想办法给原有插件添加这个功能。
      crifan6年前 (2012-08-03)回复
60 queries in 0.265 seconds, using 12.26MB memory