diff --git a/bwp-simple-gxs-ms.php b/bwp-simple-gxs-ms.php new file mode 100644 index 0000000..6a9a045 --- /dev/null +++ b/bwp-simple-gxs-ms.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/bwp-simple-gxs.php b/bwp-simple-gxs.php new file mode 100644 index 0000000..87b5ace --- /dev/null +++ b/bwp-simple-gxs.php @@ -0,0 +1,31 @@ +Sitemap index rather than a single sitemap. Despite its simplicity, it is still very powerful and has plenty of options to choose. +Version: 1.1.6 +Text Domain: bwp-simple-gxs +Domain Path: /languages/ +Author: Khang Minh +Author URI: http://betterwp.net +License: GPLv3 +*/ + +// Pre-emptive +$bwp_gxs_ob_level = @ob_get_level(); +$bwp_gxs_ob_start = ob_start(); + +// Frontend +require_once(dirname(__FILE__) . '/includes/class-bwp-simple-gxs.php'); +$bwp_gxs_gzipped = (!BWP_SIMPLE_GXS::is_gzipped()) ? false : true; +$bwp_gxs = new BWP_SIMPLE_GXS(); + +// Backend +add_action('admin_menu', 'bwp_gxs_init_admin', 1); + +function bwp_gxs_init_admin() +{ + global $bwp_gxs; + $bwp_gxs->init_admin(); +} +?> \ No newline at end of file diff --git a/bwp-simple-gxs.pot b/bwp-simple-gxs.pot new file mode 100644 index 0000000..97ad5f8 --- /dev/null +++ b/bwp-simple-gxs.pot @@ -0,0 +1,615 @@ +msgid "" +msgstr "" +"Project-Id-Version: BWP Google XML Sitemaps\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-09-20 12:59+0700\n" +"PO-Revision-Date: 2011-09-20 12:59+0700\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-KeywordsList: _;gettext;gettext_noop;__;_e\n" +"X-Poedit-Basepath: .\n" +"X-Poedit-SourceCharset: utf-8\n" +"X-Poedit-SearchPath-0: .\n" + +#: includes/class-bwp-framework.php:172 +#, php-format +msgid "%s requires WordPress %s or higher and PHP %s or higher. The plugin will not function until you update your software. Please deactivate this plugin." +msgstr "" + +#: includes/class-bwp-framework.php:183 +msgid "Development Log" +msgstr "" + +#: includes/class-bwp-framework.php:183 +msgid "Frequently Asked Questions" +msgstr "" + +#: includes/class-bwp-framework.php:183 +msgid "FAQ" +msgstr "" + +#: includes/class-bwp-framework.php:183 +msgid "Got a problem? Send me a feedback!" +msgstr "" + +#: includes/class-bwp-framework.php:183 +msgid "Contact" +msgstr "" + +#: includes/class-bwp-framework.php:190 +msgid "You can buy me some special coffees if you appreciate my work, thank you!" +msgstr "" + +#: includes/class-bwp-framework.php:204 +msgid "Donate to " +msgstr "" + +#: includes/class-bwp-framework.php:206 +msgid "One cup $5.00" +msgstr "" + +#: includes/class-bwp-framework.php:207 +msgid "Two cups $10.00" +msgstr "" + +#: includes/class-bwp-framework.php:208 +msgid "Five cups! $25.00" +msgstr "" + +#: includes/class-bwp-framework.php:209 +msgid "One LL-cup!!! $50.00" +msgstr "" + +#: includes/class-bwp-framework.php:210 +msgid "... or any amount!" +msgstr "" + +#: includes/class-bwp-framework.php:225 +msgid "Latest updates from BetterWP.net!" +msgstr "" + +#: includes/class-bwp-framework.php:226 +msgid "Follow me on Twitter!" +msgstr "" + +#: includes/class-bwp-framework.php:235 +#, php-format +msgid "You are using version %s!" +msgstr "" + +#: includes/class-bwp-framework.php:372 +msgid "Settings" +msgstr "" + +#: includes/class-bwp-gxs-cache.php:34 +#, php-format +msgid "Cache directory (\"%s\") does not exist or is not writable." +msgstr "" + +#: includes/class-bwp-gxs-cache.php:56 +#, php-format +msgid "Cache file for module %s is not found and will be built right away." +msgstr "" + +#: includes/class-bwp-gxs-cache.php:108 +#: includes/class-bwp-simple-gxs.php:1121 +#, php-format +msgid "Successfully served a cached version of %s.xml." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:129 +#: includes/class-bwp-simple-gxs.php:310 +msgid "Sitemap Statistics" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:130 +#: includes/class-bwp-simple-gxs.php:311 +msgid "Sitemap Generator" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:149 +#, php-format +msgid "This sitemap was originally generated in %s second(s) (Memory usage: %s) - %s queries - %s URL(s) listed" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:308 +msgid "BWP Google XML Sitemaps" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:310 +msgid "BWP Google XML Sitemaps Statistics" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:311 +msgid "BWP Google XML Sitemaps Generator" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:322 +msgid "You do not have sufficient permissions to access this page." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:343 +#: includes/class-bwp-simple-gxs.php:587 +#: includes/class-bwp-simple-gxs.php:589 +msgid "Notice" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:343 +msgid "All logs have been cleared successfully!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:350 +msgid "What are Sitemaps?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:351 +msgid "Your sitemaps" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:352 +msgid "Submit your sitemaps" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:353 +msgid "Pinging search engines" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:354 +msgid "Enable pinging functionality?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:355 +msgid "Enable pinging individual SE" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:356 +msgid "Sitemap Generator's Log" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:357 +msgid "Enable logging?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:358 +msgid "Enable debugging?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:368 +msgid "In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site — http://www.sitemaps.org/" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:368 +msgid "This plugin helps you generate both Sitemap Index files as well as normal Sitemap files. A Sitemap Index, as its name suggests, is one kind of sitemaps that allows you to group multiple sitemap files inside it." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:369 +msgid "Basic information about all your sitemaps." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:370 +msgid "More detailed information about how your sitemaps are generated including notices, errors and success messages." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:371 +#, php-format +msgid "Submit your sitemapindex to major search engines like Google, Yahoo, Bing or Ask." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:372 +msgid "Now when you post something new to your blog, you can ping those search engines to tell them your blog just got updated. Pinging could be less effective than you think it is but you should enable such feature anyway." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:377 +msgid "Selected SE below will be pinged when you publish new posts." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:378 +msgid "No additional load is needed so enabling this is recommended." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:379 +msgid "Minor errors will be printed on screen. Also, when debug is on, no caching is used, useful when you develop new modules." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:380 +msgid "Google" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:381 +#, php-format +msgid "Yahoo — important" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:382 +msgid "Bing" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:383 +msgid "Ask.com" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:386 +#, php-format +msgid "After you activate this plugin, all sitemaps should be available right away. The next step is to submit the sitemapindex to major search engines. You only need the sitemapindex and nothing else, those search engines will automatically recognize other included sitemaps. You can read a small How-to if you are interested." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:414 +msgid "Output no more than" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:415 +msgid "Default change frequency" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:416 +msgid "Default priority" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:417 +msgid "Minimum priority" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:418 +msgid "Use GMT for Last Modified date?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:419 +msgid "Style your sitemaps with an XSLT stylesheet?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:420 +msgid "Custom XSLT stylesheet URL" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:421 +msgid "Show build stats in sitemaps?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:422 +msgid "Enable credit?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:423 +msgid "Enable Gzip?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:424 +msgid "Clean unexpected output before sitemap generation?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:425 +msgid "Sitemap Index Options" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:426 +msgid "Automatically split post-based sitemaps into smaller sitemaps?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:427 +msgid "Add sitemapindex to individual blog's virtual robots.txt?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:428 +msgid "Add sitemapindex from all blogs within network to primary blog's virtual robots.txt?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:429 +msgid "In sitemapindex, include" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:430 +msgid "Exclude following post types:" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:431 +msgid "Exclude following taxonomies:" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:432 +msgid "Module Options" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:433 +msgid "Alternate module directory" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:434 +msgid "Get no more than" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:435 +msgid "Caching Options" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:436 +msgid "Enable caching?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:437 +msgid "Enable auto cache re-generation?" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:438 +msgid "Cached sitemaps will last for" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:439 +msgid "Cached sitemaps are stored in (auto detected)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:443 +msgid "Cache your sitemaps for better performance." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:444 +#, php-format +msgid "This plugin uses modules to build sitemap data so it is recommended that you extend this plugin using modules rather than hooks. Some of the settings below only affect modules extending the base module class. Read more about using modules here." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:445 +msgid "Here you can change some settings that affect the default Sitemap Index file." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:459 +#: includes/class-bwp-simple-gxs.php:465 +msgid "second(s)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:460 +#: includes/class-bwp-simple-gxs.php:466 +msgid "minute(s)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:461 +#: includes/class-bwp-simple-gxs.php:467 +msgid "hour(s)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:462 +#: includes/class-bwp-simple-gxs.php:468 +msgid "day(s)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:475 +#: includes/class-bwp-simple-gxs.php:476 +#: includes/class-bwp-simple-gxs.php:477 +msgid "read more" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:480 +msgid "your sitemaps are generated and then cached to reduce unnecessary work." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:481 +msgid "when a cached sitemap expires, this plugin will try to generate the cache again. If you disable this, remember to manually flush the cache once in a while." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:481 +msgid "Flush the cache" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:482 +msgid "tell you useful information such as build time, memory usage, SQL queries, etc." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:483 +#, php-format +msgid "make your sitemaps ~ 70% smaller. Important: If you see an error after enabling this, it's very likely that you have gzip active on your server already." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:484 +msgid "only disable this when sitemaps appear in either blank page or plain text." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:485 +#, php-format +msgid "If you have like 50 blogs, 50 Sitemap: http://example.com/sitemapindex.xml entries will be added to your primary blog's robots.txt, i.e. %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:486 +msgid "taxonomy archives' sitemaps, including custom taxonomies." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:488 +msgid "date archives' sitemaps." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:489 +msgid "external pages' sitemap. This allows you to add links to pages that do not belong to WordPress to the sitemap." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:490 +msgid "some copyrighted info is also added to your sitemaps. Thanks!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:491 +msgid "This will load the default style sheet provided by this plugin. You can set a custom style sheet below or filter the bwp_gxs_xslt hook." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:492 +#, php-format +msgid "If you're on a Multi-site installation with Sub-domain enabled, each site will have its own robots.txt, sites in sub-directory will not. Please read the documentation for more info." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:493 +msgid "e.g. post1.xml, post2.xml, etc. And each sitemap will contain" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:494 +msgid "If you disable this, make sure you also use date_default_timezone_set to correctly set up a timezone for your application." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:495 +msgid "author archives' sitemap." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:496 +msgid "site's home URL sitemap. For a multi-site installation of WordPress, this sitemap will list all domains within your network, not just the main blog. This also supports WPMU Domain Mapping plugin." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:499 +msgid "item(s) in one sitemap. You can not go over 50,000." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:500 +msgid "item(s). Again , you can not go over 50,000." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:501 +msgid "Input a full path to the directory where you put your own modules (e.g. /home/mysite/public_html/gxs-modules/), you can also override a built-in module by having a module with the same filename in this directory. A filter is also available if you would like to use PHP instead." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:502 +msgid "The cache directory must be writable (i.e. CHMOD to 755 or 777)." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:503 +msgid "item(s) in one SQL query. This helps you avoid running too heavy queries." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:506 +msgid "expected to be an absolute URL, e.g. http://example.com/my-stylesheet.xsl. You must also have a style sheet for the sitemapindex that can be accessed through the above URL, e.g. my-stylesheet.xsl and my-stylesheetindex.xsl). Please leave blank if you do not wish to use." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:513 +#, php-format +msgid "Note: If you encounter white page problem, please refer to the FAQ section to know how to change this limit appropriately to make this plugin work. Also note that, for post-based sitemaps, this option will be overridden by the limit you set in the Sitemap Index Options below." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:587 +#, php-format +msgid "%d cached sitemaps have been flushed successfully!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:589 +msgid "Could not delete any cached sitemaps. Please manually check the cache directory." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:658 +msgid "Warning" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:658 +msgid "Cache directory does not exist or is not writable. Please read more about directory permission here (Unix)." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:669 +msgid "Clear All Logs" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:723 +msgid "(Debug is on)" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:736 +msgid "BWP Google XML Sitemaps Error: " +msgstr "" + +#: includes/class-bwp-simple-gxs.php:736 +msgid "BWP Google XML Sitemaps Error" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:759 +#, php-format +msgid "Nothing here... yet! Try submitting your sitemapindex first!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:759 +msgid "No log yet!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:769 +#, php-format +msgid "%s has been successfully built on %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:779 +#: includes/class-bwp-simple-gxs.php:796 +msgid "M j, Y : H:i:s" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1089 +#, php-format +msgid "Requested module (%s) not found or not allowed." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1148 +#: includes/class-bwp-simple-gxs.php:1168 +#, php-format +msgid "Loaded a custom sub-module file: %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1157 +#, php-format +msgid "Mapped sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the requested sub-module instead." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1176 +#, php-format +msgid "Sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the parent module instead." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1189 +#, php-format +msgid "Loaded a custom module file: %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1195 +#, php-format +msgid "Could not load module file: %s in both default and custom module directory. Please recheck if that module file exists." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1213 +#, php-format +msgid "There is no class named %s in the module file %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1222 +#, php-format +msgid "Loaded a custom sitemapindex module file: %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1245 +#, php-format +msgid "Successfully generated %s.xml using module %s." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1276 +msgid "BWP Google XML Sitemap Message: Unexpected output (most of the time PHP errors) is preventing BWP GXS from showing any sitemap contents. Try disabling WP_DEBUG or this plugin's debug mode, whichever is on. All unexpected outputs should be shown just above this message. If you don't see any, contact me and I might be able to help." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1382 +msgid "Unknown response code from search engines. Ping failed." +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1384 +#, php-format +msgid "Pinged %s successfully!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1389 +#, php-format +msgid "Error %s from %s" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1394 +#, php-format +msgid "Ping limit for today to %s has been reached, sorry!" +msgstr "" + +#: includes/class-bwp-simple-gxs.php:1422 +#, php-format +msgid "%s.xml does not have any item. The plugin has fired a 404 header to the search engine that requests it. You should check the module that generates that sitemap (%s.php)." +msgstr "" + +#: includes/bwp-option-page/includes/class-bwp-option-page.php:80 +msgid "Plugin Configurations" +msgstr "" + +#: includes/bwp-option-page/includes/class-bwp-option-page.php:398 +msgid "Save Changes" +msgstr "" + diff --git a/cache/.htaccess b/cache/.htaccess new file mode 100644 index 0000000..c271610 --- /dev/null +++ b/cache/.htaccess @@ -0,0 +1,4 @@ + + Order Allow,Deny + Deny from All + \ No newline at end of file diff --git a/css/bwp-simple-gxs.css b/css/bwp-simple-gxs.css new file mode 100644 index 0000000..516c8e3 --- /dev/null +++ b/css/bwp-simple-gxs.css @@ -0,0 +1,12 @@ +* html .bwp-gxs-log { + height: expression( this.scrollHeight > 200 ? "200px" : "auto" ); +} +.bwp-gxs-log { + font-size: 0.95em; + background-color: #ffffff; + padding: 5px 10px; padding-top: 0px; + width: 90%; + border: 1px solid #cccccc; + max-height: 200px; + overflow: auto; +} \ No newline at end of file diff --git a/images/icon_menu.png b/images/icon_menu.png new file mode 100644 index 0000000..0b2a4d9 Binary files /dev/null and b/images/icon_menu.png differ diff --git a/images/icon_menu_32.png b/images/icon_menu_32.png new file mode 100644 index 0000000..266f5b4 Binary files /dev/null and b/images/icon_menu_32.png differ diff --git a/includes/bwp-option-page/bwp-option-page.php b/includes/bwp-option-page/bwp-option-page.php new file mode 100644 index 0000000..d3bbafa --- /dev/null +++ b/includes/bwp-option-page/bwp-option-page.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/includes/bwp-option-page/css/bwp-option-page.css b/includes/bwp-option-page/css/bwp-option-page.css new file mode 100644 index 0000000..fb972dc --- /dev/null +++ b/includes/bwp-option-page/css/bwp-option-page.css @@ -0,0 +1,136 @@ +/* For WordPress of older versions */ +.nav-tab{border-style:solid;border-color:#ccc #ccc #f9f9f9;border-width:1px 1px 0;color:#c1c1c1;text-shadow:rgba(255,255,255,1) 0 1px 0;font-size:12px;line-height:16px;display:inline-block;padding:4px 14px 6px;text-decoration:none;margin:0 6px -1px 0;-moz-border-radius:5px 5px 0 0;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;-khtml-border-top-left-radius:5px;-khtml-border-top-right-radius:5px;border-top-left-radius:5px;border-top-right-radius:5px;}.nav-tab-active{border-width:1px;color:#464646;}h2.nav-tab-wrapper,h3.nav-tab-wrapper{border-bottom:1px solid #ccc;padding-bottom:0;}h2 .nav-tab{padding:4px 20px 6px;font:italic normal normal 24px/35px Georgia,"Times New Roman","Bitstream Charter",Times,serif;} + +.bwp-option-page { + margin-top: 1em; +} + +.bwp-option-page p { + margin-top: 0px; + margin-bottom: 0px; + zoom: 1; +} + +.bwp-option-page li.clear, .bwp-option-page div.clear { + clear: left; + margin: 1em 0 0 0; + zoom: 1; +} + +.bwp-option-page p.submit { + clear: both; + padding-top: 1.5em; +} + +.wrap .bwp-option-page-tabs { + border-bottom: 1px solid #CCCCCC; + padding-bottom: 0px; + margin-bottom: 20px; +} + +.bwp-option-page-tabs a { + font-size: 19px; +} + +.bwp-option-page-tabs a.version { + font-size: 17px; + line-height: 22px; +} + +.bwp-opton-page-label { + display: block; + float: left; + width: 200px; + margin: 3px 0 1em 0; +} + +.type-checkbox { + margin-top: 0px; +} + +p.bwp-option-page-inputs { + margin: 0 0 0 220px; + padding: 0; +} + +.bwp-option-page-inputs input { + margin: 0 0 5px 0; +} + +.bwp-option-page-inputs label { + margin: 0; +} + +.bwp-option-page-inputs select { + margin: 1px 0 0 0; +} + +.bwp-option-page-inputs input[type="checkbox"] { + margin-left: 2px; +} + +#icon-betterwp-net { + background: url("betterwp.jpg") no-repeat transparent; + border: 1px solid #E3E3E3; + height: 32px; + width: 32px; +} + +#icon-bwp-plugin { + background-repeat: no-repeat; + background-position: left center; + margin-top: 21px; margin-left: 5px; + width: 36px; +} + +#bwp-info-place { + float: right; + margin: 0 0 10px 10px; +} + +#bwp-donation, #bwp-contact { + width: 255px; + padding: 7px; padding-bottom: 0px; + background-color: #ffffff; + border: 1px solid #cccccc; + text-align: center; +} + +#bwp-donation p { + margin: 0.5em 0 1em 0; +} + +#bwp-info-place small { + font-size: 0.8em; +} + +#bwp-donation .paypal-submit { + vertical-align: bottom; + display: inline-block; + margin: 0 0 1px 2px; + padding: 0px; +} + +#bwp-seperator { + width: 271px; +} + +#bwp-contact { + text-align: left; + padding: 7px; +} + +#bwp-contact a { + display: block; + height: 20px; + font-size: 0.8em; + padding-left: 25px; +} + +#bwp-contact .bwp-rss { + background: transparent url("../images/icon-rss.png") no-repeat left center; +} + +#bwp-contact .bwp-twitter { + background: transparent url("../images/icon-twitter.png") no-repeat left center; +} \ No newline at end of file diff --git a/includes/bwp-option-page/images/icon-paypal.gif b/includes/bwp-option-page/images/icon-paypal.gif new file mode 100644 index 0000000..f48205c Binary files /dev/null and b/includes/bwp-option-page/images/icon-paypal.gif differ diff --git a/includes/bwp-option-page/images/icon-rss.png b/includes/bwp-option-page/images/icon-rss.png new file mode 100644 index 0000000..5c692a4 Binary files /dev/null and b/includes/bwp-option-page/images/icon-rss.png differ diff --git a/includes/bwp-option-page/images/icon-twitter.png b/includes/bwp-option-page/images/icon-twitter.png new file mode 100644 index 0000000..4ec11ac Binary files /dev/null and b/includes/bwp-option-page/images/icon-twitter.png differ diff --git a/includes/bwp-option-page/includes/class-bwp-option-page.php b/includes/bwp-option-page/includes/class-bwp-option-page.php new file mode 100644 index 0000000..2dc1d3c --- /dev/null +++ b/includes/bwp-option-page/includes/class-bwp-option-page.php @@ -0,0 +1,405 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER + */ + +class BWP_OPTION_PAGE { + + /** + * The form + */ + var $form; + + /** + * The form name + */ + var $form_name; + + /** + * Tabs to build + */ + var $form_tabs; + + /** + * Current tab + */ + var $current_tab; + + /** + * This holds the form items, determining the position + */ + var $form_items = array(); + + /** + * This holds the name for each items (an item can have more than one fields) + */ + var $form_item_names = array(); + + /** + * This holds the form label + */ + var $form_item_labels = array(); + + /** + * This holds the form option aka data + */ + var $form_options = array(), $site_options = array(); + + /** + * Other things + */ + var $domain; + + /** + * Constructor + */ + function __construct($form_name = 'bwp_option_page', $site_options = array(), $domain = '') + { + $this->form_name = $form_name; + $this->site_options = $site_options; + $this->domain = $domain; + } + + /** + * Init the class + * + * @param array $form The form array that contains everything we need to build the form + * @param array $options The data array that contains all data fetched from db or by default + * @param string $form_name The name of the form, change this if you have more than one forms on a page + */ + function init($form = array(), $options = array(), $form_tabs = array()) + { + $this->form_items = $form['items']; + $this->form_item_names = $form['item_names']; + $this->form_item_labels = $form['item_labels']; + $this->form = $form; + $this->form_options = $options; + $this->form_tabs = $form_tabs; + if (sizeof($this->form_tabs) == 0) + $this->form_tabs = array(__('Plugin Configurations', 'bwp-option-page')); + } + + function get_form_name() + { + return $this->form_name; + } + + function set_current_tab($current_tab = 0) + { + $this->current_tab = $current_tab; + } + + function get_options($options = array(), $options_default = array()) + { + foreach ($options_default as $key => $option) + { + if (!in_array($key, $options)) + unset($options_default[$key]); + } + return $options_default; + } + + function get_db_options($name = '', $options = array()) + { + $db_options = get_option($name); + if (!$db_options) + update_option($name, $options); + else if (array_keys($options) != array_keys($db_options)) + { + foreach ($db_options as $key => $data) + if (isset($options[$key]) && !in_array($key, $this->site_options)) + $options[$key] = $data; + update_option($name, $options); + } + else + { + foreach ($db_options as $key => $data) + if (!in_array($key, $this->site_options)) + $options[$key] = $data; + } + + return $options; + } + + function format_field($key, $option_formats) + { + if (!empty($option_formats[$key])) + { + if ('int' == $option_formats[$key]) + $_POST[$key] = (int) $_POST[$key]; + else if ('float' == $option_formats[$key]) + $_POST[$key] = (float) $_POST[$key]; + else if ('html' == $option_formats[$key]) + $_POST[$key] = wp_filter_post_kses($_POST[$key]); + } + else + $_POST[$key] = strip_tags($_POST[$key]); + } + + function kill_html_fields(&$form = array(), $ids) + { + $ids = (array) $ids; + $in_keys = array('items', 'item_labels', 'item_names'); + foreach ($ids as $id) + { + foreach ($in_keys as $key) + unset($form[$key][$id]); + } + } + + /** + * Generate HTML field + * + * @params they explain themselves + */ + function generate_html_field($type = '', $data = array(), $name = '', $in_section = false) + { + $pre_html_field = ''; + $post_html_field = ''; + $checked = 'checked="checked" '; + $selected = 'selected="selected" '; + $value = (isset($this->form_options[$name])) ? $this->form_options[$name] : ''; + $value = (!empty($this->domain) && ('textarea' == $type || 'input' == $type)) ? __($value, $this->domain) : $value; + $value = ('textarea' == $type) ? esc_html($value) : esc_attr($value); + $array_replace = array(); + $array_search = array('size', 'name', 'value', 'cols', 'rows', 'label', 'disabled', 'pre', 'post'); + $return_html = ''; + $br = (isset($this->form['inline_fields'][$name]) && is_array($this->form['inline_fields'][$name])) ? '' : "
\n"; + $pre = (!empty($data['pre'])) ? $data['pre'] : ''; + $post = (!empty($data['post'])) ? $data['post'] : ''; + + switch ($type) + { + case 'heading': + $html_field = '%s'; + break; + + case 'input': + $html_field = (!$in_section) ? '%pre% %label%' : ''; + break; + + case 'select': + $pre_html_field = '%pre%%post%' . $br; + break; + + case 'checkbox': + $html_field = ''; + break; + + case 'radio': + $html_field = ''; + break; + + case 'textarea': + $html_field = '%pre%' . $value . '%post%'; + break; + } + + if (!isset($data)) + return; + + if ($type == 'heading' && !is_array($data)) + { + $return_html .= sprintf($html_field, $data) . $br; + } + else if ($type == 'radio' || $type == 'checkbox' || $type == 'select') + { + foreach ($data as $key => $value) + { + // handle checkbox a little bit differently + if ($type == 'checkbox') + { + if ($this->form_options[$value] == 'yes') + $return_html .= str_replace(array('%value%', '%name%', '%label%', '%checked%'), array($value, $value, $key, $checked), $html_field) . $br; + else + $return_html .= str_replace(array('%value%', '%name%', '%label%', '%checked%'), array($value, $value, $key, ''), $html_field) . $br; + } + else if (isset($this->form_options[$name]) && $this->form_options[$name] == $value) + $return_html .= str_replace(array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'), array($value, $value, $key, $key, $checked, $selected, $pre, $post), $html_field) . $br; + else + $return_html .= str_replace(array('%value%', '%name%', '%label%', '%option%', '%checked%', '%selected%', '%pre%', '%post%'), array($value, $value, $key, $key, '', '', $pre, $post), $html_field) . $br; + } + } + else + { + foreach ($array_search as &$keyword) + { + $array_replace[$keyword] = ''; + if (!empty($data[$keyword])) + { + $array_replace[$keyword] = $data[$keyword]; + } + $keyword = '%' . $keyword . '%'; + } + $return_html = str_replace($array_search, $array_replace, $html_field) . $br; + } + + // inline fields + $inline_html = ''; + if (isset($this->form['inline_fields'][$name]) && is_array($this->form['inline_fields'][$name])) + { + foreach ($this->form['inline_fields'][$name] as $field => $field_type) + { + if (isset($this->form[$field_type][$field])) + $inline_html = ' ' . $this->generate_html_field($field_type, $this->form[$field_type][$field], $field, $in_section); + } + } + + // Post + $post = (!empty($this->form['post'][$name])) ? ' ' . $this->form['post'][$name] : $post; + + return str_replace('%pre%', $pre, $pre_html_field) . $return_html . str_replace('%post%', $post, $post_html_field) . $inline_html; + } + + /** + * Generate HTML fields + * + * @params they explain themselves + */ + function generate_html_fields($type, $name) + { + $item_label = ''; + $return_html = ''; + + $item_key = array_keys($this->form_item_names, $name); + + $input_class = ($type == 'heading') ? 'bwp-option-page-heading-desc' : 'bwp-option-page-inputs'; + + // An inline item can hold any HTML markup + // An example is to display some kinds of button right be low the label + $inline = ''; + if (isset($this->form['inline']) && is_array($this->form['inline']) && array_key_exists($name, $this->form['inline'])) + { + $inline = (empty($this->form['inline'][$name])) ? '' : $this->form['inline'][$name]; + } + $inline .= "\n"; + + switch ($type) + { + case 'section': + + if (!isset($this->form[$name]) || !is_array($this->form[$name])) + return; + + $item_label = '' . $this->form_item_labels[$item_key[0]] . $inline . ''; + + foreach ($this->form[$name] as $section_field) + { + $type = $section_field[0]; + $name = $section_field['name']; + + if (isset($this->form[$section_field[0]])) + { + $return_html .= $this->generate_html_field($section_field[0], $this->form[$type][$name], $name, true); + } + } + break; + + default: + + if (!isset($this->form[$type][$name]) || ($type != 'heading' && !is_array($this->form[$type][$name]))) + return; + + /*$item_label = (empty($this->form[$type][$name]['label'])) ? '' : '' . $this->form_item_labels[$item_key[0]] . '';*/ + $item_label = ($type != 'checkbox' && $type != 'radio') ? '' : '' . $this->form_item_labels[$item_key[0]] . $inline . ''; + $item_label = ($type == 'heading') ? '

' . $this->form_item_labels[$item_key[0]] . '

' . $inline : $item_label; + + if (isset($this->form[$type])) + { + $return_html = $this->generate_html_field($type, $this->form[$type][$name], $name); + } + break; + } + + // A container can hold some result executed by customized script, + // such as displaying something when user press the submit button + $containers = ''; + if (isset($this->form['container']) && is_array($this->form['container']) && array_key_exists($name, $this->form['container'])) + { + $container_array = (array) $this->form['container'][$name]; + foreach ($container_array as $container) + { + $containers .= (empty($container)) ? '
' : '
' . $container . '
' . "\n"; + } + } + + $pure_return = trim(strip_tags($return_html)); + if (empty($pure_return) && $type == 'heading') + return $item_label . $containers; + else + return $item_label . '

' . $return_html . '

' . $containers; + } + + /** + * Generate HTML form + * + * @see Constructor + */ + function generate_html_form() + { + $return_str = '
' . "\n"; + if (sizeof($this->form_tabs) >= 2) + $return_str .= apply_filters('bwp-admin-form-icon', '

' . "\n"); + else + $return_str .= '

'; + + if (sizeof($this->form_tabs) >= 2) + { + $count = 0; + $return_str .= '

' . "\n"; + $return_str .= apply_filters('bwp-admin-plugin-version', '') . "\n"; + foreach ($this->form_tabs as $title => $link) + { + $count++; + $active = ($count == $this->current_tab) ? ' nav-tab-active' : ''; + $return_str .= '' . $title . '' . "\n"; + } + $return_str .= '

' . "\n"; + } + else if (!isset($this->form_tabs[0])) + { + $title = array_keys($this->form_tabs); + $return_str .= '

' . $title[0] . '

' . "\n"; + } + else + $return_str .= '

' . $this->form_tabs[0] . '

' . "\n"; + + $return_str .= apply_filters('bwp_option_before_form', ''); + echo $return_str; + do_action('bwp_option_action_before_form'); + $return_str = ''; + $return_str .= '
' . "\n"; + if (function_exists('wp_nonce_field')) + { + echo $return_str; + wp_nonce_field($this->form_name); + $return_str = ''; + } + $return_str .= '
    ' . "\n"; + + // generate filled form + if (isset($this->form_items) && is_array($this->form_items)) + foreach ($this->form_items as $key => $type) + { + if (!empty($this->form_item_names[$key]) && !empty($this->form_item_labels[$key])) + { + $return_str .= '
  • ' . $this->generate_html_fields($type, $this->form_item_names[$key]) . '
  • ' . "\n"; + } + } + + $return_str .= '
' . "\n"; + $return_str .= apply_filters('bwp_option_before_submit_button', ''); + echo $return_str; + do_action('bwp_option_action_before_submit_button'); + $return_str = ''; + $return_str .= apply_filters('bwp_option_submit_button', '

') . "\n"; + $return_str .= '
' . "\n"; + $return_str .= '
' . "\n"; + + echo $return_str; + } +} +?> \ No newline at end of file diff --git a/includes/bwp-option-page/js/paypal.js b/includes/bwp-option-page/js/paypal.js new file mode 100644 index 0000000..a18fb5c --- /dev/null +++ b/includes/bwp-option-page/js/paypal.js @@ -0,0 +1,11 @@ +jQuery(document).ready(function(){ + /* Paypal form */ + jQuery('.paypal-form select[name="amount"]').change(function() { + if (jQuery(this).val() == '100.00') + { + jQuery(this).hide(); + jQuery('.paypal-alternate-input').append(' $'); + jQuery('.paypal-alternate-input').show(); + } + }); +}); \ No newline at end of file diff --git a/includes/class-bwp-framework.php b/includes/class-bwp-framework.php new file mode 100644 index 0000000..9cb095c --- /dev/null +++ b/includes/class-bwp-framework.php @@ -0,0 +1,455 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER + */ + +define('BWP_FRAMEWORK_VERSION', '1.0.0'); + +class BWP_FRAMEWORK { + + /** + * Database related data + */ + var $options = array(); + + /** + * Default data + */ + var $options_default = array(), $site_options = array(); + + /** + * Hold db option keys + */ + var $option_keys = array(); + + /** + * Hold extra option keys + */ + var $extra_option_keys = array(); + + /** + * Hold old option pages + */ + var $option_pages = array(); + + /** + * Key to identify plugin + */ + var $plugin_key; + + /** + * Constant Key to identify plugin + */ + var $plugin_ckey; + + /** + * Domain Key to identify plugin + */ + var $plugin_dkey; + + /** + * Title of the plugin + */ + var $plugin_title; + + /** + * Homepage of the plugin + */ + var $plugin_url; + + /** + * Plugin file + */ + var $plugin_file; + + /** + * Version of the plugin + */ + var $plugin_ver = ''; + + /** + * Message shown to user (Warning, Notes, etc.) + */ + var $notices = array(), $notice_shown = false; + + /** + * Capabilities to manage this plugin + */ + var $plugin_cap = 'manage_options'; + + /** + * Whether or not to create filter for media paths + */ + var $need_media_filters; + + /** + * Form tabs to build + */ + var $form_tabs = array(); + + /** + * Other things + */ + var $wp_ver = '2.8'; + var $php_ver = '5'; + + /** + * Build base properties + */ + function build_properties($key, $dkey, $options, $plugin_title = '', $plugin_file = '', $plugin_url = '', $need_media_filters = true) + { + $this->plugin_key = strtolower($key); + $this->plugin_ckey = strtoupper($key); + $this->plugin_dkey = $dkey; + $this->plugin_title = $plugin_title; + $this->plugin_url = $plugin_url; + // The default options + $this->options_default = $options; + $this->need_media_filters = (boolean) $need_media_filters; + $this->plugin_file = $plugin_file; + // Load locale + load_plugin_textdomain($dkey, false, basename(dirname($plugin_file)) . '/languages'); + } + + function add_option_key($key, $option, $title) + { + $this->option_keys[$key] = $option; + $this->option_pages[$key] = $title; + } + + function add_extra_option_key($key, $option, $title) + { + $this->extra_option_keys[$key] = $option; + $this->option_pages[$key] = $title; + } + + function add_icon() + { + return '
plugin_ckey . '_IMAGES') . '/icon_menu_32.png");\'>
' . "\n"; + } + + function set_version($ver = '', $type = '') + { + switch ($type) + { + case '': $this->plugin_ver = $ver; + break; + case 'php': $this->php_ver = $ver; + break; + case 'wp': $this->wp_ver = $ver; + break; + } + } + + function get_version($type = '') + { + switch ($type) + { + case '': return $this->plugin_ver; + break; + case 'php': return $this->php_ver; + break; + case 'wp': return $this->wp_ver; + break; + } + } + + function check_required_versions() + { + if (version_compare(PHP_VERSION, $this->php_ver, '<') || version_compare(get_bloginfo('version'), $this->wp_ver, '<')) + { + add_action('admin_notices', array($this, 'warn_required_versions')); + add_action('network_admin_notices', array($this, 'warn_required_versions')); + return false; + } + else + return true; + } + + function warn_required_versions() + { + echo '

' . sprintf(__('%s requires WordPress %s or higher and PHP %s or higher. The plugin will not function until you update your software. Please deactivate this plugin.', $this->plugin_dkey), $this->plugin_title, $this->wp_ver, $this->php_ver) . '

'; + } + + function show_donation() + { + $showable = apply_filters('bwp_donation_showable', true); +?> +
+
+plugin_title; ?> vplugin_ver; ?>
+ + plugin_dkey); ?>plugin_dkey); ?>plugin_dkey); ?> + +
+is_multisite() && is_super_admin())) + { +?> +plugin_dkey); ?> +
+

+ + + + + + + + + + + + + + + + +

+
+ +
+
+
+
+ +
+plugin_ver)) return ''; + return '' . $this->plugin_ver . ''; + } + + function init() + { + // Build constants + $this->build_constants(); + // Build tabs + $this->build_tabs(); + // Build options + $this->build_options(); + // Load libraries + $this->load_libraries(); + // Add actions and filters + $this->add_hooks(); + // Enqueue needed media, conditionally + $this->enqueue_media(); + // Load other properties + $this->init_properties(); + // Loaded everything for this plugin, now you can add other things to it, such as stylesheet, etc. + do_action($this->plugin_key . '_loaded'); + // Support installation and uninstallation + register_activation_hook($this->plugin_file, array($this, 'install')); + register_deactivation_hook($this->plugin_file, array($this, 'uninstall')); + // icon 32px + if ($this->is_admin_page()) + { + add_filter('bwp-admin-form-icon', array($this, 'add_icon')); + add_filter('bwp-admin-plugin-version', array($this, 'show_version')); + add_action('bwp_option_action_before_form', array($this, 'show_donation'), 12); + } + } + + function add_cap($cap) + { + $this->plugin_cap = $cap; + } + + function build_constants() + { + define($this->plugin_ckey . '_PLUGIN_URL', $this->plugin_url); + // Path + if (true == $this->need_media_filters) + { + define($this->plugin_ckey . '_IMAGES', apply_filters($this->plugin_key . '_image_path', plugin_dir_url($this->plugin_file) . 'images')); + define($this->plugin_ckey . '_CSS', apply_filters($this->plugin_key . '_css_path', plugin_dir_url($this->plugin_file) . 'css')); + define($this->plugin_ckey . '_JS', apply_filters($this->plugin_key . '_js_path', plugin_dir_url($this->plugin_file) . 'js')); + } + else + { + define($this->plugin_ckey . '_IMAGES', plugin_dir_url($this->plugin_file) . 'images'); + define($this->plugin_ckey . '_CSS', plugin_dir_url($this->plugin_file) . 'css'); + define($this->plugin_ckey . '_JS', plugin_dir_url($this->plugin_file) . 'js'); + } + // Option page related + define($this->plugin_ckey . '_CAPABILITY', $this->plugin_cap); // the capability needed to configure this plugin + + foreach ($this->option_keys as $key => $option) + { + define(strtoupper($key), $option); + } + + foreach ($this->extra_option_keys as $key => $option) + { + define(strtoupper($key), $option); + } + } + + function build_options() + { + // Get all options and merge them + $options = $this->options_default; + foreach ($this->option_keys as $option) + { + $db_option = get_option($option); + if ($db_option && is_array($db_option)) + $options = array_merge($options, $db_option); + unset($db_option); + // Also check for global options if in Multi-site + if ($this->is_multisite()) + { + $db_option = get_site_option($option); + if ($db_option && is_array($db_option)) + { + $temp = array(); + foreach ($db_option as $k => $o) + { + if (in_array($k, $this->site_options)) + $temp[$k] = $o; + } + $options = array_merge($options, $temp); + } + } + } + $this->options = $options; + } + + function init_properties() + { + /* intentionally left blank */ + } + + function load_libraries() + { + /* intentionally left blank */ + } + + function add_hooks() + { + /* intentionally left blank */ + } + + function enqueue_media() + { + /* intentionally left blank */ + } + + function install() + { + /* intentionally left blank */ + } + + function uninstall() + { + /* intentionally left blank */ + } + + function is_admin_page() + { + if (is_admin() && !empty($_GET['page']) && (in_array($_GET['page'], $this->option_keys) || in_array($_GET['page'], $this->extra_option_keys))) + return true; + } + + function plugin_action_links($links, $file) + { + $option_keys = array_values($this->option_keys); + if ($file == plugin_basename($this->plugin_file)) + $links[] = '' . __('Settings') . ''; + + return $links; + } + + function init_admin() + { + add_filter('plugin_action_links', array($this, 'plugin_action_links'), 10, 2); + + if ($this->is_admin_page()) + { + // Load option page builder + if (!class_exists('BWP_OPTION_PAGE')) + require_once(dirname(__FILE__) . '/bwp-option-page/bwp-option-page.php'); + // Enqueue style sheets and scripts for the option page + wp_enqueue_style('bwp-option-page', plugin_dir_url($this->plugin_file) . 'includes/bwp-option-page/css/bwp-option-page.css', array(), '1.0.1'); + wp_enqueue_script('bwp-paypal-js', plugin_dir_url($this->plugin_file) . 'includes/bwp-option-page/js/paypal.js', array('jquery')); + } + $this->build_menus(); + } + + /** + * Build the Menus + */ + function build_menus() + { + /* intentionally left blank */ + } + + function build_tabs() + { + foreach ($this->option_pages as $key => $page) + { + $pagelink = (!empty($this->option_keys[$key])) ? $this->option_keys[$key] : $this->extra_option_keys[$key]; + $this->form_tabs[$page] = get_option('siteurl') . '/wp-admin/admin.php?page=' . $pagelink; + } + } + + /** + * Build the option pages + * + * Utilizes BWP Option Page Builder (@see BWP_OPTION_PAGE) + */ + function build_option_pages() + { + /* intentionally left blank */ + } + + function add_notice($notice) + { + if (!in_array($notice, $this->notices)) + { + $this->notices[] = $notice; + add_action('bwp_option_action_before_form', array($this, 'show_notices')); + } + } + + function show_notices() + { + if (false == $this->notice_shown) + { + foreach ($this->notices as $notice) + { + echo '

' . $notice . '

'; + } + $this->notice_shown = true; + } + } + + function is_multisite() + { + if (function_exists('is_multisite') && is_multisite()) + return true; + return false; + } + + function is_normal_admin() + { + if ($this->is_multisite() && !is_super_admin()) + return true; + return false; + } +} +?> \ No newline at end of file diff --git a/includes/class-bwp-gxs-cache.php b/includes/class-bwp-gxs-cache.php new file mode 100644 index 0000000..c353641 --- /dev/null +++ b/includes/class-bwp-gxs-cache.php @@ -0,0 +1,136 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_CACHE { + + var $module = ''; + var $cache_dir = ''; + var $cache_file = ''; + var $cache_time = 0; + var $gzip = false; + var $has_cache = false; + var $options; + var $now; + var $cache_header = array(); + var $cache_ok = false; + + function __construct($config = array()) + { + global $bwp_gxs; + + // Init necessary config to work with the cache + $this->options = $bwp_gxs->get_options(); + $this->module = $config['module']; + $this->module_name = $config['module_name']; + $this->cache_dir = $this->options['input_cache_dir']; + $this->gzip = ('yes' == $this->options['enable_gzip']) ? true : false; + $this->cache_time = (int) $this->options['input_cache_age'] * (int) $this->options['select_time_type']; + $this->now = time(); + + if (empty($this->cache_dir) || !@is_writable($this->cache_dir)) + $bwp_gxs->elog(sprintf(__('Cache directory ("%s") does not exist or is not writable.', 'bwp-simple-gxs'), $this->cache_dir)); + else + $this->setup_cache(); + } + + function get_header() + { + return $this->cache_header; + } + + function get_cache_file() + { + return $this->cache_file; + } + + function check_cache() + { + global $bwp_gxs; + + // If the cache file is not found + if (!@file_exists($this->cache_file)) + { + $bwp_gxs->nlog(sprintf(__('Cache file for module %s is not found and will be built right away.', 'bwp-simple-gxs'), $this->module)); + return false; + } + $this->has_cache = true; + + return true; + } + + function setup_cache() + { + global $bwp_gxs; + // Build cache file name, WPMS compatible + $file_name = 'gxs_' . md5($this->module . '_' . get_option('home')); + // $file_name .= (true == $this->gzip) ? '.xml.gz' : '.xml'; + // Use gz all the time to save space + $file_name .= '.xml.gz'; + $this->cache_file = trailingslashit($this->cache_dir) . $file_name; + $this->cache_ok = true; + + if ($this->check_cache()) + { + // So cache is found, check if we can still use it + $filemtime = @filemtime($this->cache_file); + if ($filemtime + $this->cache_time <= $this->now && 'yes' == $this->options['enable_cache_auto_gen']) + { + @unlink($this->cache_file); + $this->has_cache = false; + } + + if (!$this->has_cache) + { + $header['lastmod'] = $bwp_gxs->format_header_time($this->now); + $header['expires'] = $bwp_gxs->format_header_time($this->now + $this->cache_time); + $header['etag'] = md5($header['expires'] . $this->cache_file); + } + else + { + $header['lastmod'] = $bwp_gxs->format_header_time($filemtime); + $header['expires'] = $bwp_gxs->format_header_time($filemtime + $this->cache_time); + $header['etag'] = md5($header['expires'] . $this->cache_file); + } + + $this->cache_header = $header; + + if ('yes' == $this->options['enable_debug']) + return; + + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) + { + if ((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $header['lastmod']) || + (isset($_SERVER['HTTP_IF_NONE_MATCH']) && str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == $header['etag'])) + { + $bwp_gxs->slog(sprintf(__('Successfully served a cached version of %s.xml.', 'bwp-simple-gxs'), $this->module_name), true); + $bwp_gxs->commit_logs(); + header('HTTP/1.1 304 Not Modified'); + exit(); + } + } + } + } + + function write_cache() + { + global $bwp_gxs; + + $file = $this->cache_file; + + $handle = @gzopen($file, 'wb'); + @flock($handle, LOCK_EX); + @gzwrite($handle, $bwp_gxs->output); + @flock($handle, LOCK_UN); + @gzclose($handle); + + @umask(0000); + @chmod($file, 0666); + + return true; + } +} + +?> \ No newline at end of file diff --git a/includes/class-bwp-gxs-module.php b/includes/class-bwp-gxs-module.php new file mode 100644 index 0000000..0eeeab5 --- /dev/null +++ b/includes/class-bwp-gxs-module.php @@ -0,0 +1,421 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE VERSION 3.0 OR LATER + */ + +class BWP_GXS_MODULE { + + /** + * Data used to build a sitemap + */ + var $data = array(); + + /** + * Is this a sitemapindex or a url set? + */ + var $type = 'url'; + + /** + * Priority mapping + */ + var $freq_to_pri = array('always' => 1.0, 'hourly' => 0.8, 'daily' => 0.7, 'weekly' => 0.6, 'monthly' => 0.4, 'yearly' => 0.3, 'never' => 0.2); + + var $comment_count = 0, $now, $offset = 0, $url_sofar = 0, $circle = 0; + var $perma_struct = '', $post_type = NULL; + + function __contruct() + { + /* Intetionally left blank */ + } + + function set_current_time() + { + $this->now = (int) time(); + } + + function init_data($pre_data = array()) + { + global $bwp_gxs; + + if (empty($this->now)) + $this->set_current_time(); + + $data['location'] = ''; + $data['lastmod'] = (!empty($pre_data['lastmod'])) ? strtotime($pre_data['lastmod']) - $bwp_gxs->oldest_time : $this->now - $bwp_gxs->oldest_time; + $data['lastmod'] = $this->format_lastmod($data['lastmod']); + + if (empty($pre_data) || sizeof($pre_data) == 0) + return $data; + + if (isset($pre_data['freq'])) $data['freq'] = $pre_data['freq']; + if (isset($pre_data['priority'])) $data['priority'] = $pre_data['priority']; + + return $data; + } + + function get_xml_link($slug) + { + global $bwp_gxs; + + if (!$bwp_gxs->use_permalink) + return get_option('home') . '/?' . $bwp_gxs->query_var_non_perma . '=' . $slug; + else + { + $permalink = get_option('permalink_structure'); + // If user is using index.php in their permalink structure, we will have to include it also + $indexphp = (strpos($permalink, 'index.php') === false) ? '' : '/index.php'; + return get_option('home') . $indexphp . '/' . $slug . '.xml'; + } + } + + /** + * Calculate the change frequency for a specific item. + * + * @copyright (c) 2006 - 2009 www.phpbb-seo.com + */ + function cal_frequency($item = '', $lastmod = '') + { + global $bwp_gxs; + + if (empty($this->now)) + $this->now = $this->set_current_time(); + + $lastmod = (is_object($item)) ? $item->post_modified : $lastmod; + + if (empty($lastmod)) + $freq = $bwp_gxs->options['select_default_freq']; + else + { + $time = $this->now - strtotime($lastmod); + $freq = $time > 30000000 ? 'yearly' : ($time > 2592000 ? 'monthly' : ($time > 604800 ? 'weekly' : ($time > 86400 ? 'daily' : ($time > 43200 ? 'hourly' : 'always')))); + } + return apply_filters('bwp_gxs_freq', $freq, $item); + } + + /** + * Calculate the priority for a specific item. + * + * This is just a basic way to calculate priority and module should use its own function instead. + * Search engines don't really care about priority and change frequency much, do they ;)? + */ + function cal_priority($item, $freq = 'daily') + { + global $bwp_gxs; + + if (empty($this->now)) + $this->now = $this->set_current_time(); + + if (!is_object($item)) // determine score by change frequency + $score = $this->freq_to_pri[$freq]; + else + { + $comment = (!empty($item->comment_count)) ? $item->comment_count : 1; + // There is no magic behind this, number of comments and freshness define priority + // yes, 164 is a lucky (and random) number :). Actually this number works well with current Unix Timestamp, + // which is larger than 13m. + $score = $this->now + ($this->now - (int) strtotime($item->post_modified)) / $comment * 164; + $score = $this->now / $score; + } + + $score = ($score < $bwp_gxs->options['select_min_pri']) ? $bwp_gxs->options['select_min_pri'] : $score; + + // For people who doesn't like using module + return apply_filters('bwp_gxs_priority_score', $score, $item, $freq); + } + + function format_lastmod($lastmod) + { + global $bwp_gxs; + if ('yes' == $bwp_gxs->options['enable_gmt']) + return gmdate('Y-m-d\TH:i:s' . '+00:00', (int) $lastmod); + else + return date('Y-m-d\TH:i:s' . '+00:00', (int) $lastmod); + } + + function post_type_uses($post_type, $taxonomy_object) + { + if (isset($taxonomy_object->object_type) && is_array($taxonomy_object->object_type) && in_array($post_type, $taxonomy_object->object_type)) + return true; + return false; + } + + function get_post_by_post_type($post_type, $result) + { + if (!isset($result) || !is_array($result)) + return false; + + for ($i = 0; $i < sizeof($result); $i++) + { + $post = $result[$i]; + if ($post_type == $post->post_type) + return $post; + } + + return false; + } + + function sort_data_by($column = 'lastmod') + { + if (!isset($this->data[0][$column])) + return false; + // Obtain a list of columns + $lastmod = array(); + for ($i = 0; $i < sizeof($this->data); $i++) + $lastmod[$i] = $this->data[$i][$column]; + // Add $data as the last parameter, to sort by the common key + array_multisort($lastmod, SORT_DESC, $this->data); + } + + /** + * Get term links without using any SQL queries and the cache. + */ + function get_term_link($term, $taxonomy = '') + { + global $wp_rewrite; + + $taxonomy = $term->taxonomy; + $termlink = $wp_rewrite->get_extra_permastruct($taxonomy); + $slug = $term->slug; + $t = get_taxonomy($taxonomy); + + if (empty($termlink)) + { + if ('category' == $taxonomy) + $termlink = '?cat=' . $term->term_id; + elseif ($t->query_var) + $termlink = "?$t->query_var=$slug"; + else + $termlink = "?taxonomy=$taxonomy&term=$slug"; + $termlink = home_url($termlink); + } + else + { + if ($t->rewrite['hierarchical'] && !empty($term->parent)) + { + $hierarchical_slugs = array(); + $ancestors = get_ancestors($term->term_id, $taxonomy); + foreach ((array)$ancestors as $ancestor) + { + $ancestor_term = get_term($ancestor, $taxonomy); + $hierarchical_slugs[] = $ancestor_term->slug; + } + $hierarchical_slugs = array_reverse($hierarchical_slugs); + $hierarchical_slugs[] = $slug; + $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink); + } + else + { + $termlink = str_replace("%$taxonomy%", $slug, $termlink); + } + $termlink = home_url( user_trailingslashit($termlink, 'category') ); + } + + // Back Compat filters. + if ('post_tag' == $taxonomy) + $termlink = apply_filters('tag_link', $termlink, $term->term_id); + elseif ('category' == $taxonomy) + $termlink = apply_filters('category_link', $termlink, $term->term_id); + + return apply_filters('term_link', $termlink, $term, $taxonomy); + } + + function get_post_permalink($leavename = false, $sample = false) + { + global $wp_rewrite, $post; + + if (is_wp_error($post)) + return $post; + + $post_link = $wp_rewrite->get_extra_permastruct($post->post_type); + $slug = $post->post_name; + $draft_or_pending = isset($post->post_status) && in_array($post->post_status, array('draft', 'pending', 'auto-draft')); + $post_type = get_post_type_object($post->post_type); + + if (!empty($post_link) && (!$draft_or_pending || $sample)) + { + if (!$leavename) + $post_link = str_replace("%$post->post_type%", $slug, $post_link); + $post_link = home_url(user_trailingslashit($post_link)); + } + else + { + if ($post_type->query_var && (isset($post->post_status) && !$draft_or_pending)) + $post_link = add_query_arg($post_type->query_var, $slug, ''); + else + $post_link = add_query_arg(array('post_type' => $post->post_type, 'p' => $post->ID), ''); + $post_link = home_url($post_link); + } + + return apply_filters('post_type_link', $post_link, $post, $leavename, $sample); + } + + function get_permalink($leavename = false) + { + global $post; + + $rewritecode = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + $leavename? '' : '%postname%', + '%post_id%', + '%category%', + '%author%', + $leavename? '' : '%pagename%', + ); + + if (!isset($post) || !is_object($post)) + return ''; + + $custom_post_types = get_post_types(array('_builtin' => false)); + if (!isset($this->post_type)) + $this->post_type = get_post_type_object($post->post_type); + + if ('post' != $post->post_type && !in_array($post->post_type, $custom_post_types)) + return ''; + + if (in_array($post->post_type, $custom_post_types)) + { + if ($this->post_type->hierarchical) + { + wp_cache_add($post->ID, $post, 'posts'); + return get_post_permalink($post->ID, $leavename); + } + else + return $this->get_post_permalink(); + } + + // In case module author doesn't initialize this variable + $permalink = (empty($this->perma_struct)) ? get_option('permalink_structure') : $this->perma_struct; + $permalink = apply_filters('pre_post_link', $permalink, $post, $leavename); + if ('' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft'))) + { + $unixtime = strtotime($post->post_date); + $category = ''; + if (strpos($permalink, '%category%') !== false) + { + // If this post belongs to a category with a parent, we have to rely on WordPress to build our permalinks + // This can cause white page for sites that have a lot of posts, don't blame this plugin, blame WordPress ;) + if (empty($post->slug) || !empty($post->parent)) + { + $cats = get_the_category($post->ID); + if ($cats) + { + usort($cats, '_usort_terms_by_ID'); // order by ID + $category = $cats[0]->slug; + if ($parent = $cats[0]->parent) + $category = get_category_parents($parent, false, '/', true) . $category; + } + } + else + $category = (strpos($permalink, '%category%') !== false) ? $post->slug : ''; + + if (empty($category)) + { + $default_category = get_category( get_option( 'default_category' ) ); + $category = is_wp_error($default_category) ? '' : $default_category->slug; + } + } + + $author = ''; + if (strpos($permalink, '%author%') !== false) + { + $authordata = get_userdata($post->post_author); + $author = $authordata->user_nicename; + } + + $date = explode(' ', date('Y m d H i s', $unixtime)); + $rewritereplace = + array( + $date[0], + $date[1], + $date[2], + $date[3], + $date[4], + $date[5], + $post->post_name, + $post->ID, + $category, + $author, + $post->post_name + ); + + $permalink = home_url(str_replace($rewritecode, $rewritereplace, $permalink)); + $permalink = user_trailingslashit($permalink, 'single'); + } + else // if they're not using the fancy permalink option + $permalink = home_url('?p=' . $post->ID); + + return apply_filters('post_link', $permalink, $post, $leavename); + } + + /** + * Always call this function when you query for something. + * + * $query_str should be already escaped using either $wpdb->escape() or $wpdb->prepare(). + */ + function get_results($query_str) + { + global $bwp_gxs, $wpdb; + + $start = (!empty($this->url_sofar)) ? $this->offset + (int) $this->url_sofar : $this->offset; + $end = (int) $bwp_gxs->options['input_sql_limit']; + $limit = (empty($this->part)) ? $bwp_gxs->options['input_item_limit'] : $bwp_gxs->options['input_split_limit_post']; + // If we exceed the actual limit, limit $end to the correct limit - @since 1.1.5 + if ($this->url_sofar + $end > $limit) + $end = $limit - $this->url_sofar; + $query_str = trim($query_str); + $query_str .= ' LIMIT ' . $start . ',' . $end; + + return $wpdb->get_results($query_str); + } + + /** + * Always call this function when you query for something. + * + * $query_str should be similar to what WP_Query accepts. + */ + function query_posts($query_str) + { + $this->circle += 1; + if (is_array($query_str)) + { + $query_str['posts_per_page'] = (int) $bwp_gxs->options['input_sql_limit']; + $query_str['paged'] = $this->circle; + } + else if (is_string($query_str)) + { + $query_str = trim($query_str); + $query_str .= '&posts_per_page=' . (int) $bwp_gxs->options['input_sql_limit']; + $query_str .= '&paged=' . $this->circle; + } + $query = new WP_Query($query_str); + return $query; + } + + function generate_data() + { + return false; + } + + function build_data($sort_column = '') + { + global $bwp_gxs; + + // Use part limit or global item limit - @since 1.1.0 + $limit = (empty($this->part)) ? $bwp_gxs->options['input_item_limit'] : $bwp_gxs->options['input_split_limit_post']; + $this->offset = (empty($this->part)) ? 0 : ($this->part - 1) * $bwp_gxs->options['input_split_limit_post']; + + while ($this->url_sofar < $limit && false != $this->generate_data()) + $this->url_sofar = sizeof($this->data); + + // Sort the data by preference + if (!empty($sort_column)) + $this->sort_data_by($sort_column); + } +} +?> \ No newline at end of file diff --git a/includes/class-bwp-simple-gxs.php b/includes/class-bwp-simple-gxs.php new file mode 100644 index 0000000..d3dd0b5 --- /dev/null +++ b/includes/class-bwp-simple-gxs.php @@ -0,0 +1,1519 @@ + + * + * 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 3 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +if (!class_exists('BWP_FRAMEWORK')) + require_once(dirname(__FILE__) . '/class-bwp-framework.php'); + +class BWP_SIMPLE_GXS extends BWP_FRAMEWORK { + + /** + * Debugging the plugin + */ + var $debug = true, $logs = array('log' => array(), 'sitemap' => array()); + + /** + * Modules to load when generating sitemapindex + */ + var $allowed_modules = array(), $requested_modules = array(); + + /** + * Directory to load modules from + */ + var $module_directory = ''; + + /** + * The permalink structure for sitemap files + */ + var $module_url = array(); + + /** + * Frequency & priority + */ + var $frequency = array('always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never'); + var $priority = array('0.1' => 0.1, '0.2' => 0.2, '0.3' => 0.3, '0.4' => 0.4, '0.5' => 0.5, '0.6' => 0.6, '0.7' => 0.7, '0.8' => 0.8, '0.9' => 0.9, '1.0' => 1.0); + + /** + * Other properties + */ + var $post_types, $taxonomies, $terms, $cache_time, $module_data, $output, $output_num = 0, $num_log = 25; + var $templates = array(), $module_map = array(); + var $sitemap_alias = array(), $use_permalink = true, $query_var_non_perma = ''; + var $ping_per_day = 100, $timeout = 3; + var $xslt = '', $xslt_index = ''; + // @since 1.0.1 + var $build_data = array('time', 'mem', 'query'); + + /** + * Constructor + */ + function __construct($version = '1.1.5') + { + // Plugin's title + $this->plugin_title = 'BWP Google XML Sitemaps'; + // Plugin's version + $this->set_version($version); + $this->set_version('3.0', 'wp'); + // Basic version checking + if (!$this->check_required_versions()) + return; + + // Default options + $options = array( + 'enable_cache' => 'yes', + 'enable_cache_auto_gen' => 'yes', + 'enable_gzip' => '', + 'enable_php_clean' => 'yes', + 'enable_xslt' => 'yes', + 'enable_sitemap_date' => '', + 'enable_sitemap_taxonomy' => 'yes', + 'enable_sitemap_external' => '', + 'enable_sitemap_split_post' => 'yes', + 'enable_sitemap_author' => '', + 'enable_sitemap_site' => 'yes', + 'enable_stats' => 'yes', + 'enable_credit' => 'yes', + 'enable_ping' => 'yes', + 'enable_ping_google' => 'yes', + 'enable_ping_yahoo' => 'yes', + 'enable_ping_bing' => 'yes', + 'enable_ping_ask' => '', + 'enable_log' => 'yes', + 'enable_debug' => '', + 'enable_robots' => 'yes', + 'enable_global_robots' => '', + 'enable_gmt' => 'yes', + 'input_exclude_post_type' => '', + 'input_exclude_taxonomy' => 'post_tag', + 'input_cache_age' => 1, + 'input_item_limit' => 5000, + 'input_split_limit_post' => 5000, + 'input_alt_module_dir' => $this->uni_path_sep(ABSPATH), + 'input_oldest' => 7, + 'input_sql_limit' => 1000, + 'input_custom_xslt' => '', + 'select_output_type' => 'concise', + 'select_time_type' => 3600, + 'select_oldest_type' => 16400, + 'select_default_freq' => 'daily', + 'select_default_pri' => 1.0, + 'select_min_pri' => 0.1, + 'input_cache_dir' => '', + 'input_ping' => array( + 'google' => 'http://www.google.com/webmasters/sitemaps/ping?sitemap=%s', + 'yahoo' => 'http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=%s', + 'bing' => 'http://www.bing.com/webmaster/ping.aspx?siteMap=%s', + 'ask' => 'http://submissions.ask.com/ping?sitemap=%s'), + 'input_sitemap_url' => '', + 'input_sitemap_struct' => '' + ); + // Super admin only options + $this->site_options = array('enable_robots', 'enable_global_robots', 'enable_log', 'enable_debug', 'enable_ping', 'enable_ping_google', 'enable_ping_yahoo', 'enable_ping_bing', 'enable_ping_ask', 'enable_gzip', 'enable_php_clean', 'enable_cache', 'enable_cache_auto_gen', 'input_cache_age', 'input_alt_module_dir', 'input_sql_limit', 'input_cache_dir', 'select_time_type'); + + $this->build_properties('BWP_GXS', 'bwp-simple-gxs', $options, 'BWP Google XML Sitemaps', dirname(dirname(__FILE__)) . '/bwp-simple-gxs.php', 'http://betterwp.net/wordpress-plugins/google-xml-sitemaps/', false); + + $this->add_option_key('BWP_GXS_STATS', 'bwp_gxs_stats', __('Sitemap Statistics', 'bwp-simple-gxs')); + $this->add_option_key('BWP_GXS_OPTION_GENERATOR', 'bwp_gxs_generator', __('Sitemap Generator', 'bwp-simple-gxs')); + + define('BWP_GXS_LOG', 'bwp_gxs_log'); + define('BWP_GXS_PING', 'bwp_gxs_ping_data'); + + $this->init(); + } + + function init_properties() + { + $this->module_directory = plugin_dir_path($this->plugin_file) . 'includes/modules/'; + + $this->templates = array( + 'sitemap' => "\n\t" . '' . "\n\t\t" . '%s%s' . "\n\t" . '', + 'url' => "\n\t" . '' . "\n\t\t" . '%1$s%2$s%3$s%4$s' . "\n\t" . '', + 'lastmod' => "\n\t\t" . '%s', + 'changefreq' => "\n\t\t" . '%s', + 'priority' => "\n\t\t" . '%.1f', + 'xslt_style' => '', + 'stats' => "\n" . '' + /*'stats_cached' => "\n" . ''*/ + ); + + $this->init_gzip(); + + $this->cache_time = (int) $this->options['input_cache_age'] * (int) $this->options['select_time_type']; + $this->oldest_time = (int) $this->options['input_oldest'] * (int) $this->options['select_oldest_type']; + $this->options['input_cache_dir'] = plugin_dir_path($this->plugin_file) . 'cache/'; + $this->options['input_cache_dir'] = $this->uni_path_sep($this->options['input_cache_dir']); + + $module_map = apply_filters('bwp_gxs_module_mapping', array()); + $this->module_map = wp_parse_args($module_map, array('post_format' => 'post_tag')); + + // Logs + $this->logs = get_option(BWP_GXS_LOG); + if (!$this->logs) + $this->logs = array('log' => array(), 'sitemap' => array()); + foreach ($this->logs as $key => $log) + if (is_array($log) && $this->num_log < sizeof($log)) + { + $log = array_slice($log, (-1) * $this->num_log); + $this->logs[$key] = $log; + } + + // Sitemap based on permastruct + $permalink = get_option('permalink_structure'); + if (!$permalink) + { + $this->use_permalink = false; + $this->query_var_non_perma = apply_filters('bwp_gxs_query_var_non_perma', 'bwpsitemap'); + $this->options['input_sitemap_url'] = home_url() . '/?' . $this->query_var_non_perma . '=sitemapindex'; + $this->options['input_sitemap_struct'] = home_url() . '/?' . $this->query_var_non_perma . '=%s'; + } + else + { + // If user is using index.php in their permalink structure, we will have to include it also + $indexphp = (strpos($permalink, 'index.php') === false) ? '' : '/index.php'; + $this->options['input_sitemap_url'] = home_url() . $indexphp . '/sitemapindex.xml'; + $this->options['input_sitemap_struct'] = home_url() . $indexphp . '/%s.xml'; + } + + // No more than 50000 URLs per sitemap + if (50000 < (int) $this->options['input_item_limit']) + $this->options['input_item_limit'] = 50000; + + // Limit per split sitemap - @since 1.1.0 + // Not higher than 50000 URLs and must be >= SQL cycling limit + if ($this->options['input_split_limit_post'] < $this->options['input_sql_limit']) + $this->options['input_split_limit_post'] = $this->options['input_sql_limit']; + if (50000 < (int) $this->options['input_split_limit_post']) + $this->options['input_split_limit_post'] = 50000; + + // XSLT style sheet + if ('yes' == $this->options['enable_xslt']) + { + // If the host the user is using is different from what we get from 'home' option, we need to use the host + // so user won't see a style sheet error, which is most of the time mistaken as broken sitemaps - @since 1.1.0 + $user_host = strtolower($_SERVER['HTTP_HOST']); + $blog_home = @parse_url(home_url()); + $blog_host = strtolower($blog_home['host']); + $this->xslt = (!empty($this->options['input_custom_xslt'])) ? $this->options['input_custom_xslt'] : plugin_dir_url($this->plugin_file) . 'xsl/bwp-sitemap.xsl'; + $this->xslt = ($user_host == $blog_host) ? $this->xslt : str_replace($blog_host, $user_host, $this->xslt); + add_action('init', array($this, 'late_init'), 99999); + } + + // Some stats + $this->build_stats['mem'] = memory_get_usage(); + } + + function late_init() + { + $this->xslt = apply_filters('bwp_gxs_xslt', $this->xslt); + $this->xslt_index = (empty($this->xslt)) ? '' : str_replace('.xsl', 'index.xsl', $this->xslt); + // Update from 1.1.4 to 1.1.5 + /*$db_options = get_option(BWP_GXS_OPTION_GENERATOR); + if (!isset($db_options['enable_sitemap_site'])) + self::flush_rewrite_rules();*/ + } + + function enqueue_media() + { + if (is_admin()) + wp_enqueue_style('bwp-gxs-admin', BWP_GXS_CSS . '/bwp-simple-gxs.css'); + } + + function insert_query_vars($vars) + { + if (!$this->use_permalink) + array_push($vars, $this->query_var_non_perma); + else + { + array_push($vars, 'gxs_module'); + array_push($vars, 'gxs_sub_module'); + } + return $vars; + } + + function insert_rewrite_rules($rules) + { + // More compatible with blogs that are set up with sitemap.xml - @since 1.0.1 + $rewrite_rules = array( + 'sitemap\.xml$' => 'index.php?gxs_module=sitemapindex', + 'sitemapindex\.xml$' => 'index.php?gxs_module=sitemapindex', + 'site\.xml$' => 'index.php?gxs_module=site', + 'page\.xml$' => 'index.php?gxs_module=page', + 'post\.xml$' => 'index.php?gxs_module=post', + 'author\.xml$' => 'index.php?gxs_module=author', + '([a-z0-9]+)_([a-z0-9_-]+)\.xml$' => 'index.php?gxs_module=$matches[1]&gxs_sub_module=$matches[2]' + ); + // @since 1.0.3 + $custom_rules = apply_filters('bwp_gxs_rewrite_rules', array()); + $rules = array_merge($custom_rules, $rewrite_rules, $rules); + return $rules; + } + + private static function flush_rewrite_rules() + { + global $wp_rewrite; + $wp_rewrite->flush_rules(); + } + + function add_hooks() + { + add_filter('rewrite_rules_array', array($this, 'insert_rewrite_rules')); + add_filter('query_vars', array($this, 'insert_query_vars')); + add_action('parse_request', array($this, 'request_sitemap')); + if ('yes' == $this->options['enable_ping']) + { + add_action('draft_to_publish', array($this, 'ping'), 1000); + add_action('new_to_publish', array($this, 'ping'), 1000); + add_action('pending_to_publish', array($this, 'ping'), 1000); + add_action('future_to_publish', array($this, 'ping'), 1000); + } + if ('yes' == $this->options['enable_robots']) + { + add_filter('robots_txt', array($this, 'do_robots'), 1000, 2); + } + } + + function install() + { + global $wp_rewrite; + $wp_rewrite->flush_rules(); + } + + function uninstall() + { + global $wp_rewrite; + $this->logs = array('log' => array(), 'sitemap' => array()); + $this->commit_logs(); + $wp_rewrite->flush_rules(); + } + + /** + * Build the Menus + */ + function build_menus() + { + add_menu_page(__('BWP Google XML Sitemaps', 'bwp-simple-gxs'), 'BWP GXS', BWP_GXS_CAPABILITY, BWP_GXS_STATS, array($this, 'build_option_pages'), BWP_GXS_IMAGES . '/icon_menu.png'); + // Sub menus + add_submenu_page(BWP_GXS_STATS, __('BWP Google XML Sitemaps Statistics', 'bwp-simple-gxs'), __('Sitemap Statistics', 'bwp-simple-gxs'), BWP_GXS_CAPABILITY, BWP_GXS_STATS, array($this, 'build_option_pages')); + add_submenu_page(BWP_GXS_STATS, __('BWP Google XML Sitemaps Generator', 'bwp-simple-gxs'), __('Sitemap Generator', 'bwp-simple-gxs'), BWP_GXS_CAPABILITY, BWP_GXS_OPTION_GENERATOR, array($this, 'build_option_pages')); + } + + /** + * Build the option pages + * + * Utilizes BWP Option Page Builder (@see BWP_OPTION_PAGE) + */ + function build_option_pages() + { + if (!current_user_can(BWP_GXS_CAPABILITY)) + wp_die(__('You do not have sufficient permissions to access this page.')); + + // Init the class + $page = $_GET['page']; + $bwp_option_page = new BWP_OPTION_PAGE($page, $this->site_options); + + $options = array(); + $dynamic_options = array(); + +if (!empty($page)) +{ + if ($page == BWP_GXS_STATS) + { + $bwp_option_page->set_current_tab(1); + + // Clear logs = @since 1.1.0 + if (isset($_POST['clear_log']) && !$this->is_normal_admin()) + { + check_admin_referer($page); + $this->logs = array('log' => array(), 'sitemap' => array()); + $this->commit_logs(); + $this->add_notice('' . __('Notice', 'bwp-simple-gxs') . ': ' . __("All logs have been cleared successfully!", 'bwp-simple-gxs')); + } + + $form = array( + 'items' => array('heading', 'heading', 'heading', 'heading', 'checkbox', 'section', 'heading', 'checkbox', 'checkbox'), + 'item_labels' => array + ( + __('What are Sitemaps?', 'bwp-simple-gxs'), + __('Your sitemaps', 'bwp-simple-gxs'), + __('Submit your sitemaps', 'bwp-simple-gxs'), + __('Pinging search engines', 'bwp-simple-gxs'), + __('Enable pinging functionality?', 'bwp-simple-gxs'), + __('Enable pinging individual SE', 'bwp-simple-gxs'), + __('Sitemap Generator\'s Log', 'bwp-simple-gxs'), + __('Enable logging?', 'bwp-simple-gxs'), + __('Enable debugging?', 'bwp-simple-gxs') + ), + 'item_names' => array('h1', 'h2', 'h4', 'h5', 'cb1', 'sec1', 'h3', 'cb2', 'cb3'), + 'sec1' => array( + array('checkbox', 'name' => 'cb4'), + array('checkbox', 'name' => 'cb5'), + array('checkbox', 'name' => 'cb6'), + array('checkbox', 'name' => 'cb7') + ), + 'heading' => array( + 'h1' => __('In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site — http://www.sitemaps.org/', 'bwp-simple-gxs') . '

' . __('This plugin helps you generate both Sitemap Index files as well as normal Sitemap files. A Sitemap Index, as its name suggests, is one kind of sitemaps that allows you to group multiple sitemap files inside it.', 'bwp-simple-gxs'), + 'h2' => __('Basic information about all your sitemaps.', 'bwp-simple-gxs'), + 'h3' => __('More detailed information about how your sitemaps are generated including notices, errors and success messages.', 'bwp-simple-gxs'), + 'h4' => sprintf(__('Submit your sitemapindex to major search engines like Google, Yahoo, Bing or Ask.', 'bwp-simple-gxs'), 'https://www.google.com/webmasters/tools/home?hl=en', 'https://siteexplorer.search.yahoo.com/mysites', 'http://www.bing.com/toolbox/webmasters/', 'http://about.ask.com/en/docs/about/webmasters.shtml#22'), + 'h5' => __('Now when you post something new to your blog, you can ping those search engines to tell them your blog just got updated. Pinging could be less effective than you think it is but you should enable such feature anyway.', 'bwp-simple-gxs') + ), + 'input' => array( + ), + 'checkbox' => array( + 'cb1' => array(__('Selected SE below will be pinged when you publish new posts.', 'bwp-simple-gxs') => 'enable_ping'), + 'cb2' => array(__('No additional load is needed so enabling this is recommended.', 'bwp-simple-gxs') => 'enable_log'), + 'cb3' => array(__('Minor errors will be printed on screen. Also, when debug is on, no caching is used, useful when you develop new modules.', 'bwp-simple-gxs') => 'enable_debug'), + 'cb4' => array(__('Google', 'bwp-simple-gxs') => 'enable_ping_google'), + 'cb5' => array(sprintf(__('Yahoo — important', 'bwp-simple-gxs'), 'http://developer.yahoo.com/blogs/ydn/posts/2010/08/api_updates_and_changes/') => 'enable_ping_yahoo'), + 'cb6' => array(__('Bing', 'bwp-simple-gxs') => 'enable_ping_bing'), + 'cb7' => array(__('Ask.com', 'bwp-simple-gxs') => 'enable_ping_ask') + ), + 'container' => array( + 'h4' => sprintf(__('After you activate this plugin, all sitemaps should be available right away. The next step is to submit the sitemapindex to major search engines. You only need the sitemapindex and nothing else, those search engines will automatically recognize other included sitemaps. You can read a small How-to if you are interested.', 'bwp-simple-gxs'), 'http://help.yahoo.com/l/us/yahoo/smallbusiness/store/promote/sitemap/sitemap-06.html'), + 'h3' => $this->get_logs(), + 'h2' => $this->get_logs(true) + ) + ); + + // Add a clear log button - @since 1.1.0 + if (!$this->is_normal_admin()) + add_filter('bwp_option_submit_button', array($this, 'add_clear_log_button')); + + // Get the options + $options = $bwp_option_page->get_options(array('enable_ping', 'enable_ping_google', 'enable_ping_yahoo', 'enable_ping_bing', 'enable_ping_ask', 'enable_log', 'enable_debug'), $this->options); + + // Get option from the database + $options = $bwp_option_page->get_db_options($page, $options); + $option_ignore = array('input_update_services'); + $option_formats = array(); + // [WPMS Compatible] + $option_super_admin = $this->site_options; + } + else if ($page == BWP_GXS_OPTION_GENERATOR) + { + $bwp_option_page->set_current_tab(2); + + $form = array( + 'items' => array('input', 'select', 'select', 'select', 'checkbox', 'checkbox', 'input', 'checkbox', 'checkbox', 'checkbox', 'checkbox', 'heading', 'checkbox', 'checkbox', 'checkbox', 'section', 'section', 'section', 'heading', 'input', 'input', 'heading', 'checkbox', 'checkbox', 'input', 'input'), + 'item_labels' => array + ( + __('Output no more than', 'bwp-simple-gxs'), + __('Default change frequency', 'bwp-simple-gxs'), + __('Default priority', 'bwp-simple-gxs'), + __('Minimum priority', 'bwp-simple-gxs'), + __('Use GMT for Last Modified date?', 'bwp-simple-gxs'), + __('Style your sitemaps with an XSLT stylesheet?', 'bwp-simple-gxs'), + __('Custom XSLT stylesheet URL', 'bwp-simple-gxs'), + __('Show build stats in sitemaps?', 'bwp-simple-gxs'), + __('Enable credit?', 'bwp-simple-gxs'), + __('Enable Gzip?', 'bwp-simple-gxs'), + __('Clean unexpected output before sitemap generation?', 'bwp-simple-gxs'), + __('Sitemap Index Options', 'bwp-simple-gxs'), + __('Automatically split post-based sitemaps into smaller sitemaps?', 'bwp-simple-gxs'), + __('Add sitemapindex to individual blog\'s virtual robots.txt?', 'bwp-simple-gxs'), + __('Add sitemapindex from all blogs within network to primary blog\'s virtual robots.txt?', 'bwp-simple-gxs'), + __('In sitemapindex, include', 'bwp-simple-gxs'), + __('Exclude following post types:', 'bwp-simple-gxs'), + __('Exclude following taxonomies:', 'bwp-simple-gxs'), + __('Module Options', 'bwp-simple-gxs'), + __('Alternate module directory', 'bwp-simple-gxs'), + __('Get no more than', 'bwp-simple-gxs'), + __('Caching Options', 'bwp-simple-gxs'), + __('Enable caching?', 'bwp-simple-gxs'), + __('Enable auto cache re-generation?', 'bwp-simple-gxs'), + __('Cached sitemaps will last for', 'bwp-simple-gxs'), + __('Cached sitemaps are stored in (auto detected)', 'bwp-simple-gxs') + ), + 'item_names' => array('input_item_limit', 'select_default_freq', 'select_default_pri', 'select_min_pri', 'cb14', 'cb10', 'input_custom_xslt', 'cb3', 'cb6', 'cb4', 'cb15', 'h5', 'cb12', 'cb11', 'cb5', 'sec1', 'sec2', 'sec3', 'h4', 'input_alt_module_dir', 'input_sql_limit', 'h3', 'cb1', 'cb2', 'input_cache_age', 'input_cache_dir'), + 'heading' => array( + 'h3' => __('Cache your sitemaps for better performance.', 'bwp-simple-gxs'), + 'h4' => sprintf(__('This plugin uses modules to build sitemap data so it is recommended that you extend this plugin using modules rather than hooks. Some of the settings below only affect modules extending the base module class. Read more about using modules here.', 'bwp-simple-gxs'), $this->plugin_url), + 'h5' => __('Here you can change some settings that affect the default Sitemap Index file.', 'bwp-simple-gxs') + ), + 'sec1' => array( + array('checkbox', 'name' => 'cb7'), + //array('checkbox', 'name' => 'cb8'), + array('checkbox', 'name' => 'cb9'), + array('checkbox', 'name' => 'cb13'), + array('checkbox', 'name' => 'cb16'), + array('checkbox', 'name' => 'cb17') + ), + 'sec2' => array(), + 'sec3' => array(), + 'select' => array( + 'select_time_type' => array( + __('second(s)', 'bwp-simple-gxs') => 1, + __('minute(s)', 'bwp-simple-gxs') => 60, + __('hour(s)', 'bwp-simple-gxs') => 3600, + __('day(s)', 'bwp-simple-gxs') => 86400 + ), + 'select_oldest_type' => array( + __('second(s)', 'bwp-simple-gxs') => 1, + __('minute(s)', 'bwp-simple-gxs') => 60, + __('hour(s)', 'bwp-simple-gxs') => 3600, + __('day(s)', 'bwp-simple-gxs') => 86400 + ), + 'select_default_freq' => array(), + 'select_default_pri' => $this->priority, + 'select_min_pri' => $this->priority + ), + 'post' => array( + 'select_default_freq' => sprintf('' . __('read more', 'bwp-simple-gxs') . '', 'http://sitemaps.org/protocol.php#xmlTagDefinitions'), + 'select_default_pri' => sprintf('' . __('read more', 'bwp-simple-gxs') . '', 'http://sitemaps.org/protocol.php#xmlTagDefinitions'), + 'select_min_pri' => sprintf('' . __('read more', 'bwp-simple-gxs') . '', 'http://sitemaps.org/protocol.php#xmlTagDefinitions') + ), + 'checkbox' => array( + 'cb1' => array(__('your sitemaps are generated and then cached to reduce unnecessary work.', 'bwp-simple-gxs') => 'enable_cache'), + 'cb2' => array(__('when a cached sitemap expires, this plugin will try to generate the cache again. If you disable this, remember to manually flush the cache once in a while.', 'bwp-simple-gxs') . ' ' => 'enable_cache_auto_gen'), + 'cb3' => array(__('tell you useful information such as build time, memory usage, SQL queries, etc.', 'bwp-simple-gxs') => 'enable_stats'), + 'cb4' => array(__('make your sitemaps ~ 70% smaller. Important: If you see an error after enabling this, it\'s very likely that you have gzip active on your server already.', 'bwp-simple-gxs') => 'enable_gzip'), + 'cb15' => array(__('only disable this when sitemaps appear in either blank page or plain text.', 'bwp-simple-gxs') => 'enable_php_clean'), + 'cb5' => array(sprintf(__("If you have like 50 blogs, 50 Sitemap: http://example.com/sitemapindex.xml entries will be added to your primary blog's robots.txt, i.e. %s.", 'bwp-simple-gxs'), get_site_option('home') . '/robots.txt') => 'enable_global_robots'), + 'cb7' => array(__("taxonomy archives' sitemaps, including custom taxonomies.", 'bwp-simple-gxs') => 'enable_sitemap_taxonomy'), + //'cb8' => array(__("tag archives' sitemap.", 'bwp-simple-gxs') => 'enable_sitemap_tag'), + 'cb9' => array(__("date archives' sitemaps.", 'bwp-simple-gxs') => 'enable_sitemap_date'), + 'cb13' => array(__("external pages' sitemap. This allows you to add links to pages that do not belong to WordPress to the sitemap.", 'bwp-simple-gxs') => 'enable_sitemap_external'), + 'cb6' => array(__('some copyrighted info is also added to your sitemaps. Thanks!', 'bwp-simple-gxs') => 'enable_credit'), + 'cb10' => array(__('This will load the default style sheet provided by this plugin. You can set a custom style sheet below or filter the bwp_gxs_xslt hook.', 'bwp-simple-gxs') => 'enable_xslt'), + 'cb11' => array(sprintf(__('If you\'re on a Multi-site installation with Sub-domain enabled, each site will have its own robots.txt, sites in sub-directory will not. Please read the documentation for more info.', 'bwp-simple-gxs'), $this->plugin_url) => 'enable_robots'), + 'cb12' => array(__('e.g. post1.xml, post2.xml, etc. And each sitemap will contain', 'bwp-simple-gxs') => 'enable_sitemap_split_post'), + 'cb14' => array(__('If you disable this, make sure you also use date_default_timezone_set to correctly set up a timezone for your application.', 'bwp-simple-gxs') => 'enable_gmt'), + 'cb16' => array(__('author archives\' sitemap.', 'bwp-simple-gxs') => 'enable_sitemap_author'), + 'cb17' => array(__('site\'s home URL sitemap. For a multi-site installation of WordPress, this sitemap will list all domains within your network, not just the main blog. This also supports WPMU Domain Mapping plugin.', 'bwp-simple-gxs') => 'enable_sitemap_site') + ), + 'input' => array( + 'input_item_limit' => array('size' => 5, 'label' => __('item(s) in one sitemap. You can not go over 50,000.', 'bwp-simple-gxs')), + 'input_split_limit_post' => array('size' => 5, 'label' => __('item(s). Again , you can not go over 50,000.', 'bwp-simple-gxs')), + 'input_alt_module_dir' => array('size' => 91, 'label' => __('Input a full path to the directory where you put your own modules (e.g. /home/mysite/public_html/gxs-modules/), you can also override a built-in module by having a module with the same filename in this directory. A filter is also available if you would like to use PHP instead.', 'bwp-simple-gxs')), + 'input_cache_dir' => array('size' => 91, 'disabled' => ' disabled="disabled"', 'label' => __('The cache directory must be writable (i.e. CHMOD to 755 or 777).', 'bwp-simple-gxs')), + 'input_sql_limit' => array('size' => 5, 'label' => __('item(s) in one SQL query. This helps you avoid running too heavy queries.', 'bwp-simple-gxs')), + 'input_oldest' => array('size' => 3, 'label' => '—'), + 'input_cache_age' => array('size' => 5, 'label' => '—'), + 'input_custom_xslt' => array('size' => 90, 'label' => __('expected to be an absolute URL, e.g. http://example.com/my-stylesheet.xsl. You must also have a style sheet for the sitemapindex that can be accessed through the above URL, e.g. my-stylesheet.xsl and my-stylesheetindex.xsl). Please leave blank if you do not wish to use.', 'bwp-simple-gxs')) + ), + 'inline_fields' => array( + 'input_cache_age' => array('select_time_type' => 'select'), + 'cb12' => array('input_split_limit_post' => 'input') + ), + 'container' => array( + 'input_item_limit' => sprintf(__('Note: If you encounter white page problem, please refer to the FAQ section to know how to change this limit appropriately to make this plugin work. Also note that, for post-based sitemaps, this option will be overridden by the limit you set in the Sitemap Index Options below.', 'bwp-simple-gxs'), $this->plugin_url . 'faq/') + ) + ); + + foreach ($this->frequency as $freq) + $changefreq[ucfirst($freq)] = $freq; + $form['select']['select_default_freq'] = $changefreq; + + // Get the options + $options = $bwp_option_page->get_options(array('input_item_limit', 'input_split_limit_post', 'input_alt_module_dir', 'input_cache_dir', 'input_sql_limit', 'input_cache_age', 'input_custom_xslt', 'input_exclude_post_type', 'input_exclude_taxonomy', 'enable_gmt', 'enable_robots', 'enable_xslt', 'enable_cache', 'enable_cache_auto_gen', 'enable_stats', 'enable_credit', 'enable_sitemap_split_post', 'enable_global_robots', 'enable_sitemap_date', 'enable_sitemap_taxonomy', 'enable_sitemap_external', 'enable_sitemap_author', 'enable_sitemap_site', 'enable_gzip', 'enable_php_clean', 'select_time_type', 'select_default_freq', 'select_default_pri', 'select_min_pri'), $this->options); + + // Get option from the database + $options = $bwp_option_page->get_db_options($page, $options); + + // Get dynamic options + if (isset($_POST['submit_' . $bwp_option_page->get_form_name()])) + { + check_admin_referer($page); + $ept = array(); $etax = array(); + foreach ($_POST as $o => $v) + { + if (strpos($o, 'ept_') === 0) + $ept[] = trim(str_replace('ept_', '', $o)); + else if (strpos($o, 'etax_') === 0) + $etax[] = trim(str_replace('etax_', '', $o)); + } + $options['input_exclude_post_type'] = implode(',', $ept); + $options['input_exclude_taxonomy'] = implode(',', $etax); + } + + // Build dynamic options + $post_types = get_post_types(array('public' => true), 'objects'); + $taxonomies = get_taxonomies(array('public' => true), ''); + $exclude_options = array( + 'post_types' => explode(',', $options['input_exclude_post_type']), + 'taxonomies' => explode(',', $options['input_exclude_taxonomy']) + ); + $dynamic_options = array(); + foreach ($post_types as $post_type) + { + if ('attachment' == $post_type->name) + continue; + $key = 'ept_' . $post_type->name; + $form['sec2'][] = array('checkbox', 'name' => $key); + $form['checkbox'][$key] = array(__($post_type->label) => $key); + if (in_array($post_type->name, $exclude_options['post_types'])) + $dynamic_options[$key] = 'yes'; + else + $dynamic_options[$key] = ''; + } + foreach ($taxonomies as $taxonomy) + { + if ('post_format' == $taxonomy->name) + continue; + $key = 'etax_' . $taxonomy->name; + $form['sec3'][] = array('checkbox', 'name' => $key); + $form['checkbox'][$key] = array(__($taxonomy->label) => $key); + if (in_array($taxonomy->name, $exclude_options['taxonomies'])) + $dynamic_options[$key] = 'yes'; + else + $dynamic_options[$key] = ''; + } + + $option_formats = array('input_item_limit' => 'int', 'input_split_limit_post' => 'int', 'input_sql_limit' => 'int', 'input_cache_age' => 'int', 'select_time_type' => 'int'); + $option_ignore = array('input_cache_dir', 'input_exclude_post_type', 'input_exclude_taxonomy'); + // [WPMS Compatible] + $option_super_admin = $this->site_options; + } +} + // Flush the cache + if (isset($_POST['flush_cache']) && !$this->is_normal_admin()) + { + check_admin_referer($page); + if ($deleted = $this->flush_cache()) + $this->add_notice('' . __('Notice', 'bwp-simple-gxs') . ': ' . sprintf(__("%d cached sitemaps have been flushed successfully!", 'bwp-simple-gxs'), $deleted)); + else + $this->add_notice('' . __('Notice', 'bwp-simple-gxs') . ': ' . __("Could not delete any cached sitemaps. Please manually check the cache directory.", 'bwp-simple-gxs')); + } + + // Get option from user input + if (isset($_POST['submit_' . $bwp_option_page->get_form_name()]) && isset($options) && is_array($options)) + { + check_admin_referer($page); + $need_flushed = false; + foreach ($options as $key => &$option) + { + $pre_option = $option; + // Get rid of options that do not have a key + if (preg_match('/^[0-9]+$/i', $key)) + { + unset($options[$key]); + continue; + } + // [WPMS Compatible] + if ($this->is_normal_admin() && in_array($key, $option_super_admin)) + {} + else if (in_array($key, $option_ignore)) + {} + else + { + if (isset($_POST[$key])) + $bwp_option_page->format_field($key, $option_formats); + if (!isset($_POST[$key])) + $option = ''; + else if (isset($option_formats[$key]) && 0 == $_POST[$key] && 'int' == $option_formats[$key]) + $option = 0; + else if (isset($option_formats[$key]) && empty($_POST[$key]) && 'int' == $option_formats[$key]) + $option = $this->options_default[$key]; + else if (!empty($_POST[$key])) + $option = trim(stripslashes($_POST[$key])); + else + $option = $this->options_default[$key]; + // Mark that we need to flush rewrite rules + if (false !== strpos($key, 'enable_sitemap_') && $pre_option != $option) + $need_flushed = true; + } + } + update_option($page, $options); + // Flush rewrite rules if needed + if ($need_flushed) + self::flush_rewrite_rules(); + // [WPMS Compatible] + if (!$this->is_normal_admin()) + update_site_option($page, $options); + } + + // [WPMS Compatible] + if (!$this->is_multisite() && $page == BWP_GXS_OPTION_GENERATOR) + $bwp_option_page->kill_html_fields($form, array(14)); + if ($this->is_normal_admin()) + { + switch ($page) + { + case BWP_GXS_OPTION_GENERATOR: + $bwp_option_page->kill_html_fields($form, array(9,10,13,14,18,19,20,21,22,23,24,25)); + break; + + case BWP_GXS_STATS: + $bwp_option_page->kill_html_fields($form, array(3,4,5,6,7,8)); + add_filter('bwp_option_submit_button', create_function('', 'return "";')); + break; + } + } + + if (!@file_exists($this->options['input_cache_dir']) || !@is_writable($this->options['input_cache_dir'])) + $this->add_notice('' . __('Warning') . ': ' . __("Cache directory does not exist or is not writable. Please read more about directory permission here (Unix).", 'bwp-simple-gxs')); + + // Assign the form and option array + $bwp_option_page->init($form, $options + $dynamic_options, $this->form_tabs); + + // Build the option page + echo $bwp_option_page->generate_html_form(); + } + + function add_clear_log_button($button) + { + $button = str_replace('

', '

', $button); + return $button; + } + + function flush_cache() + { + $dir = trailingslashit($this->options['input_cache_dir']); + $deleted = 0; + if (is_dir($dir)) + { + if ($dh = opendir($dir)) + { + while (($file = readdir($dh)) !== false) + { + if (preg_match('/^gxs_[a-z0-9]+\.(xml|xml\.gz)$/i', $file)) + { + @unlink($dir . $file); + $deleted++; + } + } + closedir($dh); + } + } + return $deleted; + } + + function get_options() + { + return $this->options; + } + + function get_current_time() + { + return current_time('timestamp'); + } + + function format_header_time($time) + { + return gmdate('D, d M Y H:i:s \G\M\T', (int) $time); + } + + function uni_path_sep($path = '') + { + return str_replace('\\', '/', $path); + } + + function commit_logs() + { + update_option(BWP_GXS_LOG, $this->logs); + } + + function do_log($message, $error = true, $sitemap = false) + { + $time = $this->get_current_time(); + $debug = ('yes' == $this->options['enable_debug']) ? __('(Debug is on)', 'bwp-simple-gxs') : ''; + if (!$sitemap && 'yes' == $this->options['enable_log'] && !empty($message)) + $this->logs['log'][] = array('log' => $message . ' ' . $debug, 'time' => $time, 'error' => $error); + else if (!is_bool($sitemap)) + $this->logs['sitemap'][$sitemap] = array('time' => $time, 'url' => $sitemap); + } + + function elog($message, $die = false, $errorCode = 503) + { + $this->do_log($message); + if (true == $die && true == $this->debug) + { + $this->commit_logs(); + wp_die(__('BWP Google XML Sitemaps Error: ', 'bwp-simple-gxs') . $message, __('BWP Google XML Sitemaps Error', 'bwp-simple-gxs'), array('response' => $errorCode)); + } + } + + function slog($message) + { + $this->do_log($message, false); + } + + function nlog($message) + { + $this->do_log($message, 'notice'); + } + + function smlog($url) + { + $this->do_log('', false, $url); + } + + function get_logs($sitemap = false) + { + $logs = (!$sitemap) ? $this->logs['log'] : $this->logs['sitemap']; + if (!$logs || !is_array($logs) || 0 == sizeof($logs)) + return ($sitemap) ? sprintf(__('Nothing here... yet! Try submitting your sitemapindex first!', 'bwp-simple-gxs'), $this->options['input_sitemap_url']) : __('No log yet!', 'bwp-simple-gxs'); + if (!$sitemap) + krsort($logs); + else + { + $log_time = array(); + foreach ($logs as $key => $row) + $log_time[$key] = $row['time']; + array_multisort($log_time, SORT_DESC, $logs); + } + $log_str = (!$sitemap) ? '
  • %s — %s
  • ' : '' . __('%s has been successfully built on %s.', 'bwp-simple-gxs') . '
    '; + $output = '
      ' . "\n"; + foreach ($logs as $log) + { + if (isset($log['error'])) + { + $color = (!is_bool($log['error']) && 'notice' == $log['error']) ? '999999' : ''; + if ('' == $color) + $color = (!$log['error']) ? '009900' : 'FF0000'; + /* translators: date format, see http://php.net/date */ + $output .= sprintf($log_str, date(__('M j, Y : H:i:s', 'bwp-simple-gxs'), $log['time']), $color, $log['log']) . "\n"; + } + else + { + // @since 1.1.5 - check for mapped domain + global $wpdb, $blog_id; + if (!empty($wpdb->dmtable) && !empty($wpdb->blogs) && $this->is_multisite()) + { + $mapped_domain = $wpdb->get_var($wpdb->prepare(' + SELECT wpdm.domain as mapped_domain FROM ' . $wpdb->blogs . ' wpblogs + INNER JOIN ' . $wpdb->dmtable . ' wpdm + ON wpblogs.blog_id = wpdm.blog_id + WHERE wpblogs.public = 1 AND wpblogs.spam = 0 AND wpblogs.deleted = 0 AND wpblogs.blog_id = %d', $blog_id)); + } + // Default to the main site's scheme + $home = @parse_url(home_url()); + $sitemap_struct = (!empty($mapped_domain)) ? str_replace($home['host'], str_replace(array('http', 'https'), '', $mapped_domain), $this->options['input_sitemap_struct']) : $this->options['input_sitemap_struct']; + $output .= sprintf($log_str, sprintf($sitemap_struct, $log['url']), $log['url'], date(__('M j, Y : H:i:s', 'bwp-simple-gxs'), $log['time'])) . "\n"; + } + } + + return $output . '
    ' . "\n"; + } + + function format_label($label) + { + return str_replace(' ', '_', strtolower($label)); + } + + function do_robots($output, $public) + { + global $blog_id, $wpdb; + + if ('0' == $public) + return $output; + + if ((defined('SUBDOMAIN_INSTALL') && true == SUBDOMAIN_INSTALL) || (isset($blog_id) && 1 == $blog_id)) + { + $output .= "\n"; + $output .= 'Sitemap: ' . $this->options['input_sitemap_url']; + $output .= "\n"; + } + // Add all other sitemapindex within the network into the primary blog's robots.txt + if ($this->is_multisite() && 'yes' == $this->options['enable_global_robots'] && isset($blog_id) && 1 == $blog_id) + { + $blogs = $wpdb->get_results("SELECT * FROM $wpdb->blogs WHERE public = 1 AND spam = 0 AND deleted = 0"); + foreach ($blogs as $blog) + { + if (1 == $blog->blog_id) + continue; + $scheme = is_ssl() ? 'https://' : 'http://'; + $path = rtrim($blog->path, '/'); + $output .= 'Sitemap: ' . str_replace(home_url(), $scheme . $blog->domain . $path, $this->options['input_sitemap_url']) . "\n"; + } + $output .= "\n"; + } + return $output; + } + + /** + * Redirect to correct domain + * + * This plugin generates sitemaps dynamically and exits before WordPress does any canonical redirection. + * This function makes sure non-www domain is redirected and vice versa. + * @since 1.0.1 + */ + function canonical_redirect($xml_slug) + { + $requested_url = is_ssl() ? 'https://' : 'http://'; + $requested_url .= $_SERVER['HTTP_HOST']; + $requested_url .= $_SERVER['REQUEST_URI']; + $original = @parse_url($requested_url); + if (false === $original) + return; + // www.example.com vs example.com + $user_home = @parse_url(home_url()); + if (!empty($user_home['host'])) + $host = $user_home['host']; + if (strtolower($original['host']) == strtolower($host) || + (strtolower($original['host']) != 'www.' . strtolower($host) && 'www.' . strtolower($original['host']) != strtolower($host))) + $host = $original['host']; + else + { + wp_redirect(sprintf($this->options['input_sitemap_struct'], $xml_slug), 301); + exit; + } + } + + /** + * A convenient function to add wanted modules or sub modules + * + * When you filter the 'bwp_gxs_modules' hook it is recommended that you use this function. + */ + function add_module($module = '', $sub_module = '') + { + if (empty($module)) + return false; + // Make sure the names are well-formed + $module = preg_replace('/[^a-z0-9-_\s]/ui', '', $module); + $module = trim(str_replace(' ', '_', $module)); + $sub_module = preg_replace('/[^a-z0-9-_\s]/ui', '', $sub_module); + $sub_module = trim(str_replace(' ', '_', $sub_module)); + if (empty($sub_module)) + $this->allowed_modules[$module] = array(); + if (!isset($this->allowed_modules[$module]) || !is_array($this->allowed_modules[$module])) + $this->allowed_modules[$module] = array($sub_module); + else if (!in_array($sub_module, $this->allowed_modules[$module])) + $this->allowed_modules[$module][] = $sub_module; + } + + /** + * A convenient function to remove unwanted modules or sub modules + * + * When you filter the 'bwp_gxs_modules' hook it is recommended that you use this function. + */ + function remove_module($module = '', $sub_module = '') + { + if (empty($module) || !isset($this->allowed_modules[$module])) + return false; + if (empty($sub_module)) + unset($this->allowed_modules[$module]); + else + { + $module = trim($module); + $sub_module = trim($sub_module); + $temp = $this->allowed_modules[$module]; + foreach ($temp as $key => $subm) + if ($sub_module == $subm) + { + unset($this->allowed_modules[$module][$key]); + return false; + } + } + } + + function allowed_modules() + { + $allowed_modules = array(); + $this->allowed_modules = &$allowed_modules; + // Site home URL sitemap - @since 1.1.5 + if ('yes' == $this->options['enable_sitemap_site']) + $this->add_module('site'); + // Module exclusion list + $excluded_post_types = explode(',', $this->options['input_exclude_post_type']); + $excluded_taxonomies = explode(',', $this->options['input_exclude_taxonomy']); + // Add public post types to module list + $post_types = $this->post_types = get_post_types(array('public' => true), 'objects'); + foreach ($this->post_types as $post_type) + { + // Page will have its own + if ('page' != $post_type->name && !in_array($post_type->name, $excluded_post_types)) + $allowed_modules['post'][] = $post_type->name; + } + // Add pages to module list + if (!in_array('page', $excluded_post_types)) + $allowed_modules['page'] = array('page'); + // Add archive pages to module list + if ('yes' == $this->options['enable_sitemap_date']) + $allowed_modules['archive'] = array('monthly', 'yearly'); + // Add taxonomies to module list + $this->taxonomies = get_taxonomies(array('public' => true), ''); + if ('yes' == $this->options['enable_sitemap_taxonomy']) + { + foreach ($this->taxonomies as $taxonomy) + if (!in_array($taxonomy->name, $excluded_taxonomies)) + $allowed_modules['taxonomy'][] = $taxonomy->name; + } + // Remove some unnecessary sitemap + $this->remove_module('post', 'attachment'); + $this->remove_module('taxonomy', 'post_format'); + $this->remove_module('taxonomy', 'nav_menu'); + // Add / Remove modules based on users' preferences + if ('yes' == $this->options['enable_sitemap_author']) + $this->add_module('author'); + if ('yes' == $this->options['enable_sitemap_external']) + $this->add_module('page', 'external'); + // Hook for a custom module list + do_action('bwp_gxs_modules_built', $this->allowed_modules, $this->post_types, $this->taxonomies); + return $this->allowed_modules; + } + + function build_requested_modules($allowed) + { + $this->requested_modules = array(); + foreach ($allowed as $module_name => $module) + { + foreach ($module as $sub_module) + { + if (isset($this->post_types[$sub_module])) // Module is a post type + { + // @since 1.0.4 - do not use label anymore, ugh + // $label = $this->format_label($this->post_types[$sub_module]->label); + $label = $this->format_label($this->post_types[$sub_module]->name); + if ('post' == $sub_module || 'page' == $sub_module || 'attachment' == $sub_module) + $data = array($label, array('post' => $this->post_types[$sub_module]->name)); + else + $data = array($module_name . '_' . $label, array('post' => $this->post_types[$sub_module]->name)); + $this->requested_modules[] = $data; + } + else if ('yes' == $this->options['enable_sitemap_taxonomy'] && isset($this->taxonomies[$sub_module])) // Module is a taxonomy + { + // $label = $this->format_label($this->taxonomies[$sub_module]->label); + $label = $this->format_label($this->taxonomies[$sub_module]->name); + $this->requested_modules[] = array($module_name . '_' . $label, array('taxonomy' => $sub_module)); + } + /*else if ('term' == $module_name) // Module is a term {} */ + else if (!empty($sub_module)) + $this->requested_modules[] = array($module_name . '_' . $sub_module, array('archive' => $sub_module)); + else + $this->requested_modules[] = array($module_name); + } + } + } + + function convert_label(&$sub_module, $module) + { + if ('taxonomy' == $module) + { + foreach ($this->taxonomies as $taxonomy) + if ($this->format_label($taxonomy->label) == $sub_module) + $sub_module = $taxonomy->name; + } + else if ('post' == $module) + { + foreach ($this->post_types as $post_type) + if ($this->format_label($post_type->label) == $sub_module) + $sub_module = $post_type->name; + } + } + + function convert_module($module) + { + preg_match('/([a-z0-9]+)_([a-z0-9_-]+)$/iu', $module, $matches); + if (0 == sizeof($matches)) + return false; + else + return $matches; + } + + function request_sitemap($wpquery) + { + // Currently requested module + if (isset($wpquery->query_vars['gxs_module'])) + { + $module = $wpquery->query_vars['gxs_module']; + $sub_module = (isset($wpquery->query_vars['gxs_sub_module'])) ? $wpquery->query_vars['gxs_sub_module'] : ''; + if (!empty($module)) + $this->load_module($module, $sub_module); + } + else if (isset($wpquery->query_vars[$this->query_var_non_perma])) + { + $module = $wpquery->query_vars[$this->query_var_non_perma]; + $parsed_module = $this->convert_module($module); + if ($parsed_module && is_array($parsed_module)) + $this->load_module($parsed_module[1], $parsed_module[2]); + else + $this->load_module($module, ''); + } + } + + function load_module($module, $sub_module) + { + // Assuming we fail, ugh! + $success = false; + // Remember to use $wpdb->prepare or $wpdb->escape when developing module + $module = stripslashes($module); + $sub_module = stripslashes($sub_module); + // Check whether or not splitting is enabled and the sub_module has a 'part' part, + // if so, remove it and pass a parameter to let the module knows that it must produce a split sitemap + $module_part = 0; + $module_virtual = ''; + if ('yes' == $this->options['enable_sitemap_split_post'] && preg_match('/part([0-9]+)$/i', $sub_module, $matches)) + { + $module_virtual = str_replace($matches[0], '', $sub_module); + $module_virtual = rtrim($module_virtual, '_'); + $module_part = (int) $matches[1]; + } + $true_sub_module = $sub_module; + $pre_module = $module; + $pre_module .= (!empty($sub_module)) ? '_' . $sub_module : ''; + // @since 1.0.1 - Redirect to correct domain, with or without www + $this->canonical_redirect($pre_module); + // Allowed modules + $allowed_modules = $this->allowed_modules(); + $this->build_requested_modules($allowed_modules); + // $this->convert_label($sub_module, $module); + if ('sitemapindex' != $module && isset($allowed_modules[$module])) + { + if (!empty($sub_module)) + { + if (in_array($sub_module, $allowed_modules[$module]) || (empty($module_virtual) && !empty($module_part) && in_array($module, $allowed_modules[$module])) || (!empty($module_virtual) && in_array($module_virtual, $allowed_modules[$module]))) + $module_key = $module . '_' . $sub_module; + else + $module_key = ''; + } + else + $module_key = $module; + $module_name = str_replace($sub_module, $true_sub_module, $module_key); + } + else if ('sitemapindex' == $module) + { + $module_key = 'sitemapindex'; + $module_name = 'sitemapindex'; + } + + // Pass the real sub_module back + $sub_module = (!empty($module_part)) ? $module_virtual : $sub_module; + + if (empty($module_key)) + { + $this->elog(sprintf(__('Requested module (%s) not found or not allowed.', 'bwp-simple-gxs'), $pre_module), true, 404); + $this->commit_logs(); + // If debugging is not enabled, redirect to homepage + wp_redirect(home_url()); + exit; + } + + // @since 1.0.1 - Start counting correct build time and queries + timer_start(); + $this->build_stats['query'] = get_num_queries(); + + // Don't let other instrusive plugins mess up our permalnks - @since 1.1.4 + remove_filter('post_link', 'syndication_permalink', 1, 3); + remove_filter('page_link', 'suffusion_unlink_page', 10, 2); + + // If cache is enabled, we check the cache first + if ('yes' == $this->options['enable_cache']) + { + require_once(dirname(__FILE__) . '/class-bwp-gxs-cache.php'); + $bwp_gxs_cache = new BWP_GXS_CACHE(array('module' => $module_key, 'module_name' => $module_name)); + // If cache is ok, output the cached sitemap, only if debug is off + if ('yes' != $this->options['enable_debug'] && true == $bwp_gxs_cache->has_cache) + { + $this->send_header($bwp_gxs_cache->get_header()); + $file = $bwp_gxs_cache->get_cache_file(); + // Decompress the gz file only if the server or script is not already gzipping, and gzip is enabled + // This is to avoid double compression + if ('yes' == $this->options['enable_gzip'] && !self::is_gzipped()) + readfile($file); + else + readgzfile($file); + // Get from cache successfully + $this->slog(sprintf(__('Successfully served a cached version of %s.xml.', 'bwp-simple-gxs'), $module_name), true); + $this->commit_logs(); + exit; + } + } + + // If the user uses a custom module dir, also check that dir for usable module files + $custom_module_dir = (!empty($this->options['input_alt_module_dir']) && $this->options_default['input_alt_module_dir'] != $this->options['input_alt_module_dir']) ? trailingslashit($this->options['input_alt_module_dir']) : false; + $custom_module_dir = trailingslashit(apply_filters('bwp_gxs_module_dir', $custom_module_dir)); + // Begin loading modules + require_once(dirname(__FILE__) . '/class-bwp-gxs-module.php'); + if ('sitemapindex' != $module && isset($allowed_modules[$module])) + { + $sub_loaded = $mapped_sub_loaded = false; + if (!empty($sub_module) && in_array($sub_module, $allowed_modules[$module])) + { + // Try to load the mapped sub-module first + if (!empty($this->module_map[$sub_module])) + { + $module_file = $module . '_' . $this->module_map[$sub_module] . '.php'; + $path_custom = ($custom_module_dir) ? $this->uni_path_sep($custom_module_dir . $module_file) : ''; + $path = $this->uni_path_sep($this->module_directory . $module_file); + if (!empty($path_custom) && @file_exists($path_custom)) + { + $module_key = $module . '_' . $this->module_map[$sub_module]; + include_once($path_custom); + $mapped_sub_loaded = true; + $this->nlog(sprintf(__('Loaded a custom sub-module file: %s.', 'bwp-simple-gxs'), $module_file)); + } + else if (@file_exists($path)) + { + $module_key = $module . '_' . $this->module_map[$sub_module]; + include_once($path); + $mapped_sub_loaded = true; + } + else // Don't fire a wp_die + $this->nlog(sprintf(__('Mapped sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the requested sub-module instead.', 'bwp-simple-gxs'), $module_file)); + } + if (false == $mapped_sub_loaded) + { + $module_file = $module . '_' . $sub_module . '.php'; + $path_custom = ($custom_module_dir) ? $this->uni_path_sep($custom_module_dir . $module_file) : ''; + $path = $this->uni_path_sep($this->module_directory . $module_file); + if (!empty($path_custom) && @file_exists($path_custom)) + { + include_once($path_custom); + $sub_loaded = true; + $this->nlog(sprintf(__('Loaded a custom sub-module file: %s.', 'bwp-simple-gxs'), $module_file)); + } + else if (@file_exists($path)) + { + include_once($path); + $sub_loaded = true; + } + else // Don't fire a wp_die + $this->nlog(sprintf(__('Sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the parent module instead.', 'bwp-simple-gxs'), $module_file)); + } + } + if (false == $sub_loaded && false == $mapped_sub_loaded) + { + // Try loading the module + $module_file = $module . '.php'; + $module_key = $module; + $path_custom = ($custom_module_dir) ? $this->uni_path_sep($custom_module_dir . $module_file) : ''; + $path = $this->uni_path_sep($this->module_directory . $module_file); + if (!empty($path_custom) && @file_exists($path_custom)) + { + include_once($path_custom); + $this->nlog(sprintf(__('Loaded a custom module file: %s.', 'bwp-simple-gxs'), $module_file)); + } + else if (@file_exists($path)) + include_once($path); + else + { + $error_log = sprintf(__('Could not load module file: %s in both default and custom module directory. Please recheck if that module file exists.', 'bwp-simple-gxs'), $module_file); + $this->elog($error_log, true); + } + } + + $this->module_data = array('module' => $module, 'sub_module' => $sub_module, 'module_key' => $module_key, 'module_name' => $module_name, 'module_part' => $module_part); + + if (class_exists('BWP_GXS_MODULE_' . $module_key)) + { + $class_name = 'BWP_GXS_MODULE_' . $module_key; + $the_module = new $class_name(); + if ('url' == $the_module->type) + $success = $this->generate_sitemap($the_module->data); + else + $success = $this->generate_sitemap_index($the_module->data); + unset($the_module->data); + } + else + $this->elog(sprintf(__('There is no class named %s in the module file %s.', 'bwp-simple-gxs'), 'BWP_GXS_MODULE_' . strtoupper($module_key), $module_file), true); + } + else if ('sitemapindex' == $module) + { + $module_file = 'sitemapindex.php'; + $path_custom = ($custom_module_dir) ? $this->uni_path_sep($custom_module_dir . $module_file) : ''; + if (!empty($path_custom) && @file_exists($path_custom)) + { + include_once($path_custom); + $this->nlog(sprintf(__('Loaded a custom sitemapindex module file: %s.', 'bwp-simple-gxs'), $module_file)); + } + else + include_once(dirname(__FILE__) . '/modules/sitemapindex.php'); + if (class_exists('BWP_GXS_MODULE_INDEX')) + { + $the_module = new BWP_GXS_MODULE_INDEX($this->requested_modules); + $success = $this->generate_sitemap_index($the_module->data); + unset($the_module->data); + } + } + + // Output succeeded + if (true == $success) + { + // Output additional stats + if ('yes' == $this->options['enable_stats']) + $this->sitemap_stats(); + // Now cache the sitemap if we have to + if ('yes' == $this->options['enable_cache'] && true == $bwp_gxs_cache->cache_ok) + $bwp_gxs_cache->write_cache(); + // Output the requested sitemap + $this->output_sitemap(); + $this->slog(sprintf(__('Successfully generated %s.xml using module %s.', 'bwp-simple-gxs'), $module_name, $module_file), true); + $this->smlog($module_name); + $this->commit_logs(); + exit; + } + else + $this->commit_logs(); + } + + function send_header($header = array()) + { + global $bwp_gxs_ob_start, $bwp_gxs_ob_level, $bwp_gxs_gzipped; + + // If debug is not enabled and gzip is not turned on in between, + // we try to clean all errors before sending new headers - @since 1.1.2 + $clean_ok = ((int) $bwp_gxs_gzipped == (int) self::is_gzipped() && 'yes' == $this->options['enable_php_clean']) ? true : false; + $ob_contents = ''; + if ($bwp_gxs_ob_start && @ob_get_level()) + { + $ob_level = @ob_get_level() - $bwp_gxs_ob_level; + while ($ob_level > 0) + { + $ob_level -= 1; + $ob_contents .= ob_get_contents(); + if ('yes' != $this->options['enable_debug'] && $clean_ok) + @ob_end_clean(); + } + } + + // If there are some contents but we can't clean them, show a friendly error + if (!empty($ob_contents) && (!$clean_ok || 'yes' == $this->options['enable_debug'])) + wp_die(__('BWP Google XML Sitemap Message: Unexpected output (most of the time PHP errors) is preventing BWP GXS from showing any sitemap contents. Try disabling WP_DEBUG or this plugin\'s debug mode, whichever is on. All unexpected outputs should be shown just above this message. If you don\'t see any, contact me and I might be able to help.', 'bwp-simple-gxs')); + + if (!empty($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache/2')) + header ('Cache-Control: no-cache, pre-check=0, post-check=0, max-age=0'); + else + header ('Cache-Control: private, pre-check=0, post-check=0, max-age=0'); + + $content_types = array('google' => 'text/xml', 'yahoo' => 'text/plain'); + + $time = time(); + $expires = $this->format_header_time($time + $this->cache_time); + + $default_headers = array( + 'lastmod' => $this->format_header_time($time), + 'expires' => $expires, + 'etag' => '' + ); + + $header = wp_parse_args($header, $default_headers); + + header('Expires: ' . $header['expires']); + header('Last-Modified: ' . $header['lastmod']); + if (!empty($header['etag'])) + header('Etag: ' . $header['etag']); + header('Accept-Ranges: bytes'); + header('Content-Type: ' . $content_types['google'] . '; charset=UTF-8'); + if ('yes' == $this->options['enable_gzip']) + header('Content-Encoding: ' . $this->check_gzip_type()); + + // Everything's cool + status_header(200); + + return; + } + + public static function is_gzipped() + { + if (ini_get('zlib.output_compression') || ini_get('output_handler') == 'ob_gzhandler' || in_array('ob_gzhandler', @ob_list_handlers())) + return true; + return false; + } + + function init_gzip() + { + if (!$this->check_gzip() && 'yes' == $this->options['enable_gzip']) + $this->options['enable_gzip'] = 'no'; + return; + } + + function check_gzip() + { + if (headers_sent()) + return false; + + if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && ((strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) + || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false)) + return true; + else + return false; + } + + function check_gzip_type() + { + if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false) + return 'gzip'; + else if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false) + return 'x-gzip'; + + return 'gzip'; + } + + function ping() + { + $time = time(); + $ping_data = get_option(BWP_GXS_PING); + if (!$ping_data || !is_array($ping_data)) + $ping_data = array( + 'data_pinged' => array('google' => 0, 'yahoo' => 0, 'bing' => 0, 'ask' => 0), + 'data_last_pinged' => array('google' => 0, 'yahoo' => 0, 'bing' => 0, 'ask' => 0) + ); + foreach ($this->options['input_ping'] as $key => $service) + { + if ('yes' == $this->options['enable_ping_' . $key]) + { + // A day has gone, reset the count + if ($time - $ping_data['data_last_pinged'][$key] > 86400) + { + $ping_data['data_pinged'][$key] = 0; + $ping_data['data_last_pinged'][$key] = $time; + } + // Ping limit has not been reached + if ($this->ping_per_day > $ping_data['data_pinged'][$key]) + { + $ping_data['data_pinged'][$key]++; + $url = sprintf($service, urlencode(str_replace('&', '&', $this->options['input_sitemap_url']))); + $response = wp_remote_post($url, array('timeout' => $this->timeout)); + if (is_wp_error($response)) + { + $errno = $response->get_error_code(); + $errorstr = $response->get_error_message(); + $this->elog($errorstr); + } + else if (isset($response['response'])) + { + $the_response = $response['response']; + if (empty($the_response['code'])) + $this->elog(__('Unknown response code from search engines. Ping failed.', 'bwp-simple-gxs')); + else if (200 == (int) $the_response['code']) + $this->slog(sprintf(__('Pinged %s successfully!', 'bwp-simple-gxs'), ucfirst($key))); + else if (200 != (int) $the_response['code']) + { + $errno = $the_response['code']; + $errorstr = $the_response['message']; + $this->elog(sprintf(__('Error %s from %s', 'bwp-simple-gxs'), $errno, ucfirst($key)) . ': ' . $errorstr); + } + } + } + else + $this->elog(sprintf(__('Ping limit for today to %s has been reached, sorry!', 'bwp-simple-gxs'), ucfirst($key))); + } + } + // Update statistics + $this->commit_logs(); + update_option(BWP_GXS_PING, $ping_data); + } + + function output_sitemap() + { + if ('yes' == $this->options['enable_gzip']) + { + $this->output = (!self::is_gzipped()) ? gzencode($this->output, 6) : $this->output; + $this->send_header(); + echo $this->output; + } + else + { + $this->send_header(); + echo $this->output; + } + } + + function check_output($output) + { + // If output is empty we log it so the user knows what's going on, but let the page load normally + if (empty($output) || 0 == sizeof($output)) + { + $this->elog(sprintf(__('%s.xml does not have any item. The plugin has fired a 404 header to the search engine that requests it. You should check the module that generates that sitemap (%s.php).', 'bwp-simple-gxs'), $this->module_data['module_name'], $this->module_data['module_key']), true, 404); + return false; + } + else + return true; + } + + function sitemap_stats($type = '') + { + $time = timer_stop(0, 3); + $sql = get_num_queries() - $this->build_stats['query']; + $memory = size_format(memory_get_usage() - $this->build_stats['mem'], 2); + if (empty($type)) + $this->output .= "\n" . sprintf($this->templates['stats'], $time, $memory, $sql, $this->output_num); + else + echo "\n" . sprintf($this->templates['stats_cached'], $time, $memory, $sql); + } + + function generate_url_item($url = '', $priority = 1.0, $freq = 'always', $lastmod = 0) + { + $freq = sprintf($this->templates['changefreq'], $freq); + $priority = str_replace(',', '.', sprintf($this->templates['priority'], $priority)); + $lastmod = (!empty($lastmod)) ? sprintf($this->templates['lastmod'], $lastmod) : ''; + if (!empty($url)) + return sprintf($this->templates['url'], $url, $lastmod, $freq, $priority); + else + return ''; + } + + function generate_sitemap_item($url = '', $lastmod = 0) + { + $lastmod = (!empty($lastmod)) ? sprintf($this->templates['lastmod'], $lastmod) : ''; + if (!empty($url)) + return sprintf($this->templates['sitemap'], $url, $lastmod); + else + return ''; + } + + function credit() + { + $xml = '' . "\n"; + return $xml; + } + + function generate_sitemap($output = array()) + { + $xml = '<' . '?xml version="1.0" encoding="UTF-8"?'.'>' . "\n"; + $xml .= (!empty($this->xslt)) ? 'xslt . '"?>' . "\n\n" : ''; + $xml .= '' . "\n"; + if ('yes' != $this->options['enable_xslt'] && 'yes' == $this->options['enable_credit']) + $xml .= $this->credit(); + + if (!$this->check_output($output)) + return false; + + foreach ($output as &$url) + { + $url['location'] = (!empty($url['location'])) ? $url['location'] : ''; + $url['lastmod'] = (!empty($url['lastmod'])) ? $url['lastmod'] : ''; + $url['freq'] = (isset($url['freq']) && in_array($url['freq'], $this->frequency)) ? $url['freq'] : $this->options['select_default_freq']; + $url['priority'] = (isset($url['priority']) && $url['priority'] <= 1 && $url['priority'] > 0) ? $url['priority'] : $this->options['select_default_pri']; + $xml .= $this->generate_url_item(htmlspecialchars($url['location']), $url['priority'], $url['freq'], $url['lastmod']); + $this->output_num++; + } + + $xml .= "\n" . ''; + $this->output = $xml; + + return true; + } + + function generate_sitemap_index($output = array()) + { + $xml = '<' . '?xml version="1.0" encoding="UTF-8"?'.'>' . "\n"; + $xml .= (!empty($this->xslt_index)) ? 'xslt_index . '"?>' . "\n\n" : ''; + $xml .= '' . "\n"; + if ('yes' != $this->options['enable_xslt'] && 'yes' == $this->options['enable_credit']) + $xml .= $this->credit(); + + if (!$this->check_output($output)) + return false; + + foreach ($output as &$sitemap) + { + $sitemap['location'] = (!empty($sitemap['location'])) ? $sitemap['location'] : ''; + $sitemap['lastmod'] = (!empty($sitemap['lastmod'])) ? $sitemap['lastmod'] : ''; + $xml .= $this->generate_sitemap_item(htmlspecialchars($sitemap['location']), $sitemap['lastmod']); + $this->output_num++; + } + + $xml .= "\n" . ''; + $this->output = $xml; + + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/archive.php b/includes/modules/archive.php new file mode 100644 index 0000000..3b9ae05 --- /dev/null +++ b/includes/modules/archive.php @@ -0,0 +1,66 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_ARCHIVE extends BWP_GXS_MODULE { + + var $requested = ''; + + function __construct() + { + global $bwp_gxs; + + $this->set_current_time(); + $this->requested = $bwp_gxs->module_data['sub_module']; + $this->build_data(); + } + + function generate_data() + { + global $wpdb; + + $requested = $this->requested; + + if ('monthly' == $requested) + $latest_post_query = ' + SELECT YEAR(post_date) AS year, MONTH(post_date) as month, COUNT(ID) as posts, comment_count, post_modified + FROM ' . $wpdb->posts . " + WHERE post_status = 'publish' AND post_type <> 'page'" . ' + GROUP BY YEAR(post_date), MONTH(post_date) + ORDER BY post_modified DESC'; + else + $latest_post_query = ' + SELECT YEAR(post_date) AS year, COUNT(ID) as posts, comment_count, post_modified + FROM ' . $wpdb->posts . " + WHERE post_status = 'publish' AND post_type <> 'page'" . ' + GROUP BY YEAR(post_date) + ORDER BY post_modified DESC'; + + $latest_posts = $this->get_results($latest_post_query); + + if (!isset($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + $data = array(); + for ($i = 0; $i < sizeof($latest_posts); $i++) + { + $post = $latest_posts[$i]; + $data = $this->init_data($data); + if ('monthly' == $requested) + $data['location'] = get_month_link($post->year, $post->month); + else if ('yearly' == $requested) + $data['location'] = get_year_link($post->year); + $data['lastmod'] = $this->format_lastmod(strtotime($post->post_modified)); + $data['freq'] = $this->cal_frequency($post); + $data['priority'] = $this->cal_priority($post, $data['freq']); + $this->data[] = $data; + } + + unset($latest_posts); + + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/author.php b/includes/modules/author.php new file mode 100644 index 0000000..51f1f76 --- /dev/null +++ b/includes/modules/author.php @@ -0,0 +1,59 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_AUTHOR extends BWP_GXS_MODULE { + + function __construct() + { + $this->set_current_time(); + $this->build_data(); + } + + function generate_data() + { + global $wpdb, $bwp_gxs; + + // An array of what roles to include in sitemap + $roles = array('administrator', 'editor', 'author'); + // The SQL query + $author_sql = 'SELECT wp_u.ID, wp_u.user_nicename, MAX(wp_p.post_modified) as lastmod, wp_um.meta_value as role + FROM ' . $wpdb->users . ' wp_u + INNER JOIN ' . $wpdb->usermeta . ' wp_um + ON wp_um.user_id = wp_u.ID + INNER JOIN ' . $wpdb->posts . ' wp_p + ON wp_p.post_author = wp_u.ID' . " + WHERE wp_p.post_status = 'publish' AND wp_um.meta_key = '" . $wpdb->prefix . "capabilities'" . ' + GROUP BY wp_u.ID, wp_u.user_nicename, wp_um.meta_value + ORDER BY lastmod DESC'; + // Get all authors + $authors = $this->get_results($author_sql); + + if (!isset($authors) || 0 == sizeof($authors)) + return false; + + $data = array(); + for ($i = 0; $i < sizeof($authors); $i++) + { + // If user is not considered an author, pass + $author = $authors[$i]; + $data = $this->init_data($data); + $role = maybe_unserialize($author->role); + $role = array_keys($role); + if (!in_array($role[0], $roles)) + continue; + $data['location'] = get_author_posts_url($author->ID, $author->user_nicename); + $data['lastmod'] = $this->format_lastmod(strtotime($author->lastmod)); + $data['freq'] = $this->cal_frequency(NULL, $author->lastmod); + $data['priority'] = $this->cal_priority(NULL, $data['freq']); + $this->data[] = $data; + } + + unset($authors); + + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/page.php b/includes/modules/page.php new file mode 100644 index 0000000..4cd4256 --- /dev/null +++ b/includes/modules/page.php @@ -0,0 +1,54 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_PAGE extends BWP_GXS_MODULE { + + function __construct() + { + global $bwp_gxs; + + $this->set_current_time(); + $this->part = $bwp_gxs->module_data['module_part']; + $this->build_data(); + } + + function generate_data() + { + global $wpdb, $bwp_gxs, $post; + + $sql_where = apply_filters('bwp_gxs_post_where', '', 'page'); + + $latest_post_query = ' + SELECT * FROM ' . $wpdb->posts . " wposts + WHERE wposts.post_status = 'publish' AND wposts.post_type = 'page' $sql_where" . ' + ORDER BY wposts.post_modified DESC'; + + $latest_posts = $this->get_results($latest_post_query); + + if (!isset($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + $data = array(); + for ($i = 0; $i < sizeof($latest_posts); $i++) + { + $post = $latest_posts[$i]; + $data = $this->init_data($data); + wp_cache_add($post->ID, $post, 'posts'); + $data['location'] = get_permalink(); + $data['lastmod'] = $this->format_lastmod(strtotime($post->post_modified)); + $data['freq'] = $this->cal_frequency($post); + $data['priority'] = $this->cal_priority($post, $data['freq']); + $this->data[] = $data; + } + + // Probably save some memory ;) + unset($latest_posts); + + // Always return true if we can get here, otherwise you're stuck at the SQL cycling limit + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/page_external.php b/includes/modules/page_external.php new file mode 100644 index 0000000..bd8987e --- /dev/null +++ b/includes/modules/page_external.php @@ -0,0 +1,43 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_PAGE_EXTERNAL extends BWP_GXS_MODULE { + + function __construct() + { + global $bwp_gxs; + + $this->set_current_time(); + $this->build_data(); + } + + function build_data() + { + global $wpdb, $bwp_gxs; + + // The structure of your external pages should be like the below sample item + // array('location' => '', 'lastmod' => '', 'priority' => '') + // Frequency will be calculated based on lastmod + $sample_pages = array( + array('location' => home_url('a-page-not-belong-to-wordpress.html'), 'lastmod' => '06/02/2011', 'priority' => '1.0'), + array('location' => home_url('another-page-not-belong-to-wordpress.html'), 'lastmod' => '05/02/2011', 'priority' => '0.8') + ); + $external_pages = (array) apply_filters('bwp_gxs_external_pages', $sample_pages); + + $data = array(); + for ($i = 0; $i < sizeof($external_pages); $i++) + { + $page = $external_pages[$i]; + $data = $this->init_data($data); + $data['location'] = $page['location']; + $data['lastmod'] = $this->format_lastmod(strtotime($page['lastmod'])); + $data['freq'] = $this->cal_frequency(NULL, $page['lastmod']); + $data['priority'] = $page['priority']; + $this->data[] = $data; + } + } +} +?> \ No newline at end of file diff --git a/includes/modules/post.php b/includes/modules/post.php new file mode 100644 index 0000000..8021283 --- /dev/null +++ b/includes/modules/post.php @@ -0,0 +1,113 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + * + * You can take this as a sample module, it is documented rather well ;) + */ + +class BWP_GXS_MODULE_POST extends BWP_GXS_MODULE { + + // Declare all properties you need for your modules here + var $requested; + + function __construct() + { + global $bwp_gxs; + // Give your properties value here + // $this->set_current_time() should always be called, it will allow you to use $this->now (the current Unix Timestamp). + $this->set_current_time(); + // $bwp_gxs->module_data hold four things, but you only need to take note of 'sub_module' and 'module_key' + // For example when you are browsing to http://example.com/taxonomy_category.xml + // $bwp_gxs->module_data['sub_module'] is 'category' (the singular name) and $bwp_gxs->module_data['module_key'] is + // 'taxonomy_category' (also singular). If you have a custom module for taxonomy_category, you must name your class + // BWP_GXS_MODULE_TAXONOMY_CATEGORY and save the file as taxonomy_category.php (similar to taxonomy_post_tag.php). + // If no custom post type is requested, use the default post type + $this->requested = (!empty($bwp_gxs->module_data['sub_module'])) ? $bwp_gxs->module_data['sub_module'] : 'post'; + // module_part let you determine whether or not to build a post sitemap as part of a large post sitemap. If this value is + // greater than 0, for example 2, or 3 it means that we are building part 2, or part 3 of that large sitemap, and we + // will have to modify our SQL query accordingly - @since 1.1.0 + $this->part = $bwp_gxs->module_data['module_part']; + // Get the permalink this website uses, apply to normal posts + $this->perma_struct = get_option('permalink_structure'); + // See if the current post_type is a hierarchical one or not + $this->post_type = get_post_type_object($this->requested); + // Always call this to start building data + // If you want to make use of SQL cycling (a method to reduce heavy queries), don't use build_data() like other modules. + // Just call it here and use function generate_data() to build actual data, just like below. Use SQL cycling when + // you are dealing with post-based sitemaps. + $this->build_data(); + } + + /** + * This is the main function that generates our data. + * + * Since we are dealing with heavy queries here, it's better that you use + * generate_data() which will get called by build_data(). This way you will query for no more than + * the SQL limit configurable in this plugin's option page. + * If you happen to use LIMIT in your SQL statement for other reasons then use build_data() instead. + */ + function generate_data() + { + global $wpdb, $bwp_gxs, $post; + + $requested = $this->requested; + + // Can be something like: ` AND wposts.ID NOT IN (1,2,3,4) ` + $sql_where = apply_filters('bwp_gxs_post_where', '', $requested); + + // A standard custom query to fetch posts from database, sorted by their lastmod + // You can use any type of queries for your modules + // If $requested is 'post' and this site uses %category% in permalink structure, + // we will have to use a complex SQL query so this plugin can scale up to millions of posts. + if ('post' == $requested && strpos($this->perma_struct, '%category%') !== false) + $latest_post_query = ' + SELECT * FROM ' . $wpdb->term_relationships . ' wprel + INNER JOIN ' . $wpdb->posts . ' wposts + ON wprel.object_id = wposts.ID' . " + AND wposts.post_status = 'publish'" . ' + INNER JOIN ' . $wpdb->term_taxonomy . ' wptax + ON wprel.term_taxonomy_id = wptax.term_taxonomy_id' . " + AND wptax.taxonomy = 'category'" . ' + , ' . $wpdb->terms . ' wpterms + WHERE wptax.term_id = wpterms.term_id ' + . "$sql_where" . ' + GROUP BY wposts.ID + ORDER BY wposts.post_modified DESC'; + else + $latest_post_query = ' + SELECT * FROM ' . $wpdb->posts . " wposts + WHERE wposts.post_status = 'publish' AND wposts.post_type = %s $sql_where" . ' + ORDER BY wposts.post_modified DESC'; + // Use $this->get_results instead of $wpdb->get_results, remember to escape your query + // using $wpdb->prepare or $wpdb->escape, @see http://codex.wordpress.org/Function_Reference/wpdb_Class + $latest_posts = $this->get_results($wpdb->prepare($latest_post_query, $requested)); + // This check helps you stop the cycling sooner + // It basically means if there is nothing to loop through anymore we return false so the cycling can stop. + if (!isset($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + // Always init your $data + $data = array(); + for ($i = 0; $i < sizeof($latest_posts); $i++) + { + $post = $latest_posts[$i]; + // Init your $data with the previous item's data. This makes sure no item is mal-formed. + $data = $this->init_data($data); + // @since 1.1.0 - get permalink independently, as we don't need caching or some complicated stuff + $data['location'] = $this->get_permalink(); + $data['lastmod'] = $this->format_lastmod(strtotime($post->post_modified)); + $data['freq'] = $this->cal_frequency($post); + $data['priority'] = $this->cal_priority($post, $data['freq']); + // Pass data back to the plugin to handle + $this->data[] = $data; + } + + // Probably save some memory ;) + unset($latest_posts); + + // Always return true if we can get here, otherwise you're stuck at the SQL cycling limit + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/post_attachment.php b/includes/modules/post_attachment.php new file mode 100644 index 0000000..0db510f --- /dev/null +++ b/includes/modules/post_attachment.php @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/includes/modules/post_most_popular.php b/includes/modules/post_most_popular.php new file mode 100644 index 0000000..0780dce --- /dev/null +++ b/includes/modules/post_most_popular.php @@ -0,0 +1,71 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + * + * This is a sample custom module. Some if about the module developer here would be nice! + */ + +class BWP_GXS_MODULE_POST_MOST_POPULAR extends BWP_GXS_MODULE { + + function __construct() + { + // Give your properties value here + // $this->set_current_time() should always be called, it will allow you to use $this->now (the current Unix Timestamp). + $this->set_current_time(); + $this->perma_struct = get_option('permalink_structure'); + // Always call this to start building data + // If you want to make use of SQL cycling (a method to reduce heavy queries), don't use build_data() like other modules. + // Just call it here and use function generate_data() to build actual data, just like below. Use SQL cycling when + // you are dealing with post-based sitemaps. + $this->build_data(); + } + + /** + * This is the main function that generates our data. + * + * Since we are dealing with heavy queries here, it's better that you use + * generate_data() which will get called by build_data(). This way you will query for no more than + * the SQL limit configurable in this plugin's option page. + * If you happen to use LIMIT in your SQL statement for other reasons then use build_data() instead. + */ + function generate_data() + { + global $wpdb, $bwp_gxs, $post; + + $latest_post_query = ' + SELECT * FROM ' . $wpdb->posts . " + WHERE post_status = 'publish' AND post_type = 'post' AND comment_count > 2" . ' + ORDER BY comment_count, post_modified DESC'; + + // Use $this->get_results instead of $wpdb->get_results, remember to escape your query + // using $wpdb->prepare or $wpdb->escape, @see http://codex.wordpress.org/Function_Reference/wpdb_Class + $latest_posts = $this->get_results($latest_post_query); + + // This check helps you stop the cycling sooner + // It basically means if there is nothing to loop through anymore we return false so the cycling can stop. + if (!isset($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + // Always init your $data + $data = array(); + for ($i = 0; $i < sizeof($latest_posts); $i++) + { + $post = $latest_posts[$i]; + // Init your $data with the previous item's data. This makes sure no item is mal-formed. + $data = $this->init_data($data); + $data['location'] = get_permalink(); + $data['lastmod'] = $this->format_lastmod(strtotime($post->post_modified)); + $data['freq'] = $this->cal_frequency($post); + $data['priority'] = $this->cal_priority($post, $data['freq']); + $this->data[] = $data; + } + + // Probably save some memory ;) + unset($latest_posts); + + // Always return true if we can get here, otherwise you're stuck at the SQL cycling limit + return true; + } +} +?> \ No newline at end of file diff --git a/includes/modules/site.php b/includes/modules/site.php new file mode 100644 index 0000000..d8aca5c --- /dev/null +++ b/includes/modules/site.php @@ -0,0 +1,76 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_SITE extends BWP_GXS_MODULE { + + function __construct() + { + $this->set_current_time(); + $this->build_data(); + } + + function generate_data() + { + global $wpdb, $blog_id; + + // If this is simply not a multisite installation, or a multisite installation, but not on main site, + // just show the lonely domain + if (empty($wpdb->blogs) || (!empty($blog_id) && 1 < $blog_id)) + { + $last_mod = $wpdb->get_var('SELECT post_modified FROM ' . $wpdb->posts . " WHERE post_status = 'publish' ORDER BY post_modified DESC"); + $data = array(); + $data['location'] = trailingslashit(home_url()); + $data['lastmod'] = $this->format_lastmod(strtotime($last_mod)); + $data['freq'] = apply_filters('bwp_gxs_freq_site', $this->cal_frequency(NULL, $last_mod), $blog_id); + $data['freq'] = ('always' == $data['freq']) ? 'hourly' : $data['freq']; + $data['priority'] = 1; + $this->data[] = $data; + return false; + } + else if (isset($blog_id) && 1 == $blog_id) + { + if (!empty($wpdb->dmtable)) + // If domain mapping is active + $blog_sql = 'SELECT wpblogs.*, wpdm.domain as mapped_domain FROM ' . $wpdb->blogs . ' wpblogs + LEFT JOIN ' . $wpdb->dmtable . ' wpdm + ON wpblogs.blog_id = wpdm.blog_id + WHERE wpblogs.public = 1 AND wpblogs.spam = 0 AND wpblogs.deleted = 0'; + else + // Otherwise + $blog_sql = 'SELECT * FROM ' . $wpdb->blogs . ' WHERE public = 1 AND spam = 0 AND deleted = 0'; + + // Get all blogs + $blogs = $this->get_results($blog_sql); + + if (!isset($blogs) || 0 == sizeof($blogs)) + return false; + + $data = array(); + for ($i = 0; $i < sizeof($blogs); $i++) + { + $blog = $blogs[$i]; + $data = $this->init_data($data); + // Get the correct domain + $scheme = is_ssl() ? 'https://' : 'http://'; + $path = $blog->path; + $data['location'] = (empty($blog->mapped_domain)) ? $scheme . $blog->domain . $path : $scheme . str_replace(array('http', 'https'), '', $blog->mapped_domain) . '/'; + $data['lastmod'] = $this->format_lastmod(strtotime($blog->last_updated)); + $data['freq'] = apply_filters('bwp_gxs_freq_site', $this->cal_frequency(NULL, $blog->last_updated), $blog->blog_id); + $data['freq'] = ('always' == $data['freq']) ? 'hourly' : $data['freq']; + // Always give primary blog a priority of 1 + $data['priority'] = (0 == $i) ? 1 : $this->cal_priority(NULL, $data['freq']); + $this->data[] = $data; + } + + unset($blogs); + + return true; + } + else + return false; + } +} +?> \ No newline at end of file diff --git a/includes/modules/sitemapindex.php b/includes/modules/sitemapindex.php new file mode 100644 index 0000000..55eda95 --- /dev/null +++ b/includes/modules/sitemapindex.php @@ -0,0 +1,143 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + */ + +class BWP_GXS_MODULE_INDEX extends BWP_GXS_MODULE { + + // Declare all properties you need for your modules here + var $requested_modules = array(); + + function __construct($requested) + { + // Give your properties value here + $this->set_current_time(); + $this->requested_modules = $requested; + // Always call this to start building data + $this->build_data(); + } + + /** + * This is the main function that generates our data. + * + * If your module deals with heavy queries, for example selecting all posts from the database, + * you should not use build_data() directly but rather use generate_data(). Open term.php for more details. + */ + function build_data() + { + global $wpdb, $bwp_gxs; + + // A better limit for sites that have posts with same last modified date - @since 1.0.2 + $limit = sizeof(get_post_types(array('public' => true))) + 1000; + + $latest_post_query = ' + SELECT * + FROM + ( + SELECT post_type, max(post_modified) AS mpmd + FROM ' . $wpdb->posts . " + WHERE post_status = 'publish'" . ' + GROUP BY post_type + ) AS f + INNER JOIN ' . $wpdb->posts . ' AS s ON s.post_type = f.post_type + AND s.post_modified = f.mpmd + LIMIT ' . (int) $limit; + $latest_posts = $wpdb->get_results($latest_post_query); + + if (!isset($latest_posts) || !is_array($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + // Build a temporary array holding post type and their latest modified date, sorted by post_modified + foreach ($latest_posts as $a_post) + $temp_posts[$a_post->post_type] = $this->format_lastmod(strtotime($a_post->post_modified)); + arsort($temp_posts); + $prime_lastmod = current($temp_posts); + + // Determine whether or not to split post-based sitemaps - @since 1.1.0 + $post_count_array = array(); + if ('yes' == $bwp_gxs->options['enable_sitemap_split_post']) + { + $post_count_query = ' + SELECT COUNT(ID) as total, post_type + FROM ' . $wpdb->posts . " + WHERE post_status = 'publish'" . ' + GROUP BY post_type + '; + $post_counts = $wpdb->get_results($post_count_query); + // Make the result array friendly + foreach ($post_counts as $count) + $post_count_array[$count->post_type] = $count->total; + unset($post_counts); + unset($count); + } + + $taxonomies = $bwp_gxs->taxonomies; + + $data = array(); + foreach ($this->requested_modules as $item) + { + $data = $this->init_data($data); + $data['location'] = $this->get_xml_link($item[0]); + $passed = false; // Whether or not to pass data back at the end + if ('site' == $item[0]) + { + // Site home URL sitemap - @since 1.1.5 + $data['lastmod'] = $prime_lastmod; + } + else if (isset($item[1])) + { + if (isset($item[1]['post'])) + { + $the_post = $this->get_post_by_post_type($item[1]['post'], $latest_posts); + if ($the_post) + { + // If we have a matching post_type and the total number of posts reach the split limit, + // we will split this post sitemap accordingly + if ('yes' == $bwp_gxs->options['enable_sitemap_split_post'] && sizeof($post_count_array) > 0 && isset($post_count_array[$the_post->post_type]) && $post_count_array[$the_post->post_type] > $bwp_gxs->options['input_split_limit_post']) + { + $num_part = floor($post_count_array[$the_post->post_type] / $bwp_gxs->options['input_split_limit_post']) + 1; + if (1 < $num_part) + { + $data['location'] = $this->get_xml_link($item[0] . '_part1'); + $data['lastmod'] = $this->format_lastmod(strtotime($the_post->post_modified)); + $this->data[] = $data; + $time_step = round(7776000 / $num_part); + $time_step = (20000 > $time_step) ? 20000 : $time_step; + for ($i = 2; $i <= $num_part; $i++) + { + $part_data['location'] = $this->get_xml_link($item[0] . '_part' . $i); + // Reduce the lastmod for about 1 month + $part_data['lastmod'] = $this->format_lastmod(strtotime($the_post->post_modified) - $i * $time_step); + $this->data[] = $part_data; + } + $passed = true; + } + else + $data['lastmod'] = $this->format_lastmod(strtotime($the_post->post_modified)); + } + else + $data['lastmod'] = $this->format_lastmod(strtotime($the_post->post_modified)); + } + } + else if (isset($item[1]['taxonomy'])) + { + foreach ($temp_posts as $post_type => $modified_time) + { + if ($this->post_type_uses($post_type, $taxonomies[$item[1]['taxonomy']])) + $data['lastmod'] = $this->format_lastmod(strtotime($modified_time)); + } + } + else if (isset($item[1]['archive'])) + $data['lastmod'] = $prime_lastmod; + } + // Just in case something went wrong - @since 1.0.2 + if (empty($data['lastmod'])) + $data['lastmod'] = $prime_lastmod; + // Pass data back to the plugin + if (false == $passed) + $this->data[] = $data; + } + } +} +?> \ No newline at end of file diff --git a/includes/modules/taxonomy.php b/includes/modules/taxonomy.php new file mode 100644 index 0000000..b9824e8 --- /dev/null +++ b/includes/modules/taxonomy.php @@ -0,0 +1,94 @@ + + * @license http://www.gnu.org/licenses/gpl.html GNU GENERAL PUBLIC LICENSE + * Taxonomy Linear Mode + */ + +class BWP_GXS_MODULE_TAXONOMY extends BWP_GXS_MODULE { + + function __construct() + { + $this->set_current_time(); + $this->build_data('lastmod'); + } + + function generate_data() + { + global $wpdb, $bwp_gxs; + + $requested = $bwp_gxs->module_data['sub_module']; + + $latest_post_query = ' + SELECT MAX(wposts.post_modified) as post_modified, MAX(wposts.comment_count) as comment_count, wptax.term_id FROM ' . $wpdb->term_relationships . ' wprel + INNER JOIN ' . $wpdb->posts . ' wposts + ON wprel.object_id = wposts.ID + INNER JOIN ' . $wpdb->term_taxonomy . ' wptax + ON wprel.term_taxonomy_id = wptax.term_taxonomy_id' . " + WHERE wposts.post_status = 'publish'" . ' + AND wptax.taxonomy = %s + AND wptax.count > 0 + GROUP BY wptax.term_id + ORDER BY wptax.term_id DESC'; + $latest_posts = $this->get_results($wpdb->prepare($latest_post_query, $requested)); + + if (!isset($latest_posts) || 0 == sizeof($latest_posts)) + return false; + + $term_query = ' + SELECT t.*, tt.* + FROM ' . $wpdb->terms . ' AS t + INNER JOIN ' . $wpdb->term_taxonomy . ' AS tt + ON t.term_id = tt.term_id + WHERE tt.taxonomy = %s AND tt.count > 0 + ORDER BY t.term_id DESC'; + $terms = $this->get_results($wpdb->prepare($term_query, $requested)); + + if (!isset($terms) || 0 == sizeof($terms)) + return false; + + // Can be something like array('cat1', 'cat2', 'cat3') + $exclude_terms = (array) apply_filters('bwp_gxs_term_exclude', array(''), $requested); + // Build an array with term_id as key + $term2post = array(); + for ($i = 0; $i < sizeof($latest_posts); $i++) + { + $post = $latest_posts[$i]; + if (!empty($post->term_id) && !isset($term2post[$post->term_id])) + $term2post[$post->term_id] = $post; + unset($post); + } + + $data = array(); + for ($i = 0; $i < sizeof($terms); $i++) + { + $term = $terms[$i]; + if (in_array($term->slug, $exclude_terms)) + continue; + $data = $this->init_data($data); + $data['location'] = $this->get_term_link($term, $requested); + if (isset($term2post[$term->term_id])) + { + $post = $term2post[$term->term_id]; + $data['lastmod'] = $this->format_lastmod(strtotime($post->post_modified)); + $data['freq'] = $this->cal_frequency($post); + $data['priority'] = $this->cal_priority($post, $data['freq']); + } + else + { + $data['freq'] = $this->cal_frequency('', $data['lastmod']); + $data['priority'] = $this->cal_priority('', $data['freq']); + } + $this->data[] = $data; + unset($post); + unset($term); + } + + unset($latest_posts); + unset($term2post); + unset($terms); + + return true; + } +} +?> \ No newline at end of file diff --git a/languages/bwp-simple-gxs-ms_MY.mo b/languages/bwp-simple-gxs-ms_MY.mo new file mode 100644 index 0000000..4ddb89e Binary files /dev/null and b/languages/bwp-simple-gxs-ms_MY.mo differ diff --git a/languages/bwp-simple-gxs-ms_MY.po b/languages/bwp-simple-gxs-ms_MY.po new file mode 100644 index 0000000..a722a47 --- /dev/null +++ b/languages/bwp-simple-gxs-ms_MY.po @@ -0,0 +1,487 @@ +msgid "" +msgstr "" +"Project-Id-Version: BWP Google XML Sitemaps(Malay Translation)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-04-15 03:56+0700\n" +"PO-Revision-Date: 2011-04-19 10:00+0700\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-KeywordsList: _;gettext;gettext_noop;__;_e\n" +"X-Poedit-Basepath: .\n" +"X-Poedit-SourceCharset: utf-8\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: Malay\n" +"X-Poedit-Country: MALAYSIA\n" +"X-Poedit-SearchPath-0: .\n" + +#: includes/class-bwp-framework.php:172 +#, php-format +msgid "%s requires WordPress %s or higher and PHP %s or higher. The plugin will not function until you update your software. Please deactivate this plugin." +msgstr "%s memerlukan WordPress %s atau yang terbaharu dan PHP %s atau yang terbaharu . Plugin ini tidak akan berfungsi sehingga anda menaiktaraf perisian. Sila nyahaktifkan plugin ini." + +#: includes/class-bwp-framework.php:181 +msgid "log" +msgstr "log" + +#: includes/class-bwp-framework.php:186 +msgid "You can buy me some coffees if you appreciate my work, thank you!" +msgstr "Anda boleh menderma jika anda hargai kerja saya, terima kasih!" + +#: includes/class-bwp-framework.php:211 +#, php-format +msgid "You are using version %s!" +msgstr "Anda menggunakan versi %s!" + +#: includes/class-bwp-framework.php:343 +msgid "Settings" +msgstr "Tetapan" + +#: includes/class-bwp-gxs-cache.php:34 +#, php-format +msgid "Cache directory (\"%s\") does not exist or is not writable." +msgstr "Direktori cache (\"%s\") tidak wujud atau tidak boleh dibaca." + +#: includes/class-bwp-gxs-cache.php:56 +#, php-format +msgid "Cache file for module %s is not found and will be built right away." +msgstr "Fail cache untuk modul %s tidak dijumpai dan akan dibina segera." + +#: includes/class-bwp-gxs-cache.php:106 +#: includes/class-bwp-simple-gxs.php:859 +#, php-format +msgid "Successfully served a cached version of %s.xml." +msgstr "Berjaya melayan versi cache untuk %s.xml." + +#: includes/class-bwp-simple-gxs.php:119 +#: includes/class-bwp-simple-gxs.php:259 +msgid "Sitemap Statistics" +msgstr "Statistik Pelan Tapak" + +#: includes/class-bwp-simple-gxs.php:120 +#: includes/class-bwp-simple-gxs.php:260 +msgid "Sitemap Generator" +msgstr "Penghasilan Pelan Tapak" + +#: includes/class-bwp-simple-gxs.php:139 +#, php-format +msgid "This sitemap was originally generated in %s second(s) (Memory usage: %s) - %s queries - %s URL(s) listed" +msgstr "Peta tapak ini asalnya telah dihasilkan selama %s saat (Penggunaan memori: %s) - %s maklumat - %s URL(s) telah disenaraikan" + +#: includes/class-bwp-simple-gxs.php:257 +msgid "BWP Google XML Sitemaps" +msgstr "Pelan Tapak Google XML BWP " + +#: includes/class-bwp-simple-gxs.php:259 +msgid "BWP Google XML Sitemaps Statistics" +msgstr "Statistik Pelan Tapak Google XML BWP " + +#: includes/class-bwp-simple-gxs.php:260 +msgid "BWP Google XML Sitemaps Generator" +msgstr "Penghasilan Pelan Tapak Google XML BWP" + +#: includes/class-bwp-simple-gxs.php:271 +msgid "You do not have sufficient permissions to access this page." +msgstr "Anda tidak mempunyai cukup kebenaran untuk mengakses muka ini." + +#: includes/class-bwp-simple-gxs.php:289 +msgid "What are Sitemaps?" +msgstr "Apa itu Pelan tapak?" + +#: includes/class-bwp-simple-gxs.php:290 +msgid "Your sitemaps" +msgstr "Pelan tapak anda" + +#: includes/class-bwp-simple-gxs.php:291 +msgid "Submit your sitemaps" +msgstr "Serah pelan tapak anda" + +#: includes/class-bwp-simple-gxs.php:292 +msgid "Pinging search engines" +msgstr "Penghantaran ke enjin carian" + +#: includes/class-bwp-simple-gxs.php:293 +msgid "Enable pinging functionality?" +msgstr "Benarkan keberkesanan penghantaran? " + +#: includes/class-bwp-simple-gxs.php:294 +msgid "Enable pinging individual SE" +msgstr "Benarkan penghantaran SE individu" + +#: includes/class-bwp-simple-gxs.php:295 +msgid "Sitemap Generator's Log" +msgstr "Log Penghasilan Pelan Tapak" + +#: includes/class-bwp-simple-gxs.php:296 +msgid "Enable logging?" +msgstr "Benarkan log?" + +#: includes/class-bwp-simple-gxs.php:297 +msgid "Enable debugging?" +msgstr "Benarkan debugging?" + +#: includes/class-bwp-simple-gxs.php:307 +msgid "In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site — http://www.sitemaps.org/" +msgstr "Dalam erti kata mudah, sebuah pelan tapak adalah fail XML yang mengandungi senarai URL untuk halaman bersama-sama dengan metadata tambahan tentang setiap URL (saat terakhir dikemaskinikan, seberapa kerap perubahan biasanya, dan betapa pentingnya, berkait rapat dengan URL lain di tapak ) jadi enjin carian akan lebih berkesan mencari tapak tersebut - http://www.sitemaps.org/" + +#: includes/class-bwp-simple-gxs.php:308 +msgid "Basic information about all your sitemaps." +msgstr "Maklumat asas tentang keseluruhan pelan tapak anda." + +#: includes/class-bwp-simple-gxs.php:309 +msgid "More detailed information about how your sitemaps are generated including notices, errors and success messages." +msgstr "Maklumat lebih lanjut tentang bagaimana pelan tapak anda telah dihasilkan termasuk notices, ralat dan juga mesej berjaya." + +#: includes/class-bwp-simple-gxs.php:310 +#, php-format +msgid "Submit your sitemapindex to major search engines like Google, Yahoo, Bing or Ask." +msgstr "Hantar indeks pelan tapak anda kepada enjin carian biasa seperti Google, Yahoo, Bing atau Ask." + +#: includes/class-bwp-simple-gxs.php:311 +msgid "Now when you post something new to your blog, you can ping those search engines to tell them your blog just got updated. Pinging could be less effective than you think it is but you should enable such feature anyway." +msgstr "Sekarang apabila anda menghantar sesuatu yang baru pada blog anda, anda boleh menguji enjin carian untuk memberitahu mereka bahawa blog anda baru dikemaskinikan. Penghantaran mungkin kurang efektif dari yang anda fikir tetapi anda harus juga benarkan fungsi ini." + +#: includes/class-bwp-simple-gxs.php:316 +msgid "Selected SE below will be pinged when you publish new posts." +msgstr "SE yang dipilih dibawah akan dihantar apabila anda menerbitkan pos baharu." + +#: includes/class-bwp-simple-gxs.php:317 +msgid "No additional load is needed so enabling this is recommended." +msgstr "Tiada beban tambahan diperlukan jadi membenarkan ini adalah digalakkan." + +#: includes/class-bwp-simple-gxs.php:318 +msgid "Minor errors will be printed on screen. Also, when debug is on, no caching is used, useful when you develop new modules." +msgstr "Ralat kecil akan dicetak pada skrin. Juga, apabila debug diaktifkan, tiada caching akan digunakan, berguna apabila anda mengembangkan modul baharu." + +#: includes/class-bwp-simple-gxs.php:319 +msgid "Google" +msgstr "Google" + +#: includes/class-bwp-simple-gxs.php:320 +#, php-format +msgid "Yahoo — important" +msgstr "Yahoo — penting" + +#: includes/class-bwp-simple-gxs.php:321 +msgid "Bing" +msgstr "Bing" + +#: includes/class-bwp-simple-gxs.php:322 +msgid "Ask.com" +msgstr "Ask.com" + +#: includes/class-bwp-simple-gxs.php:325 +#, php-format +msgid "After you activate this plugin, all sitemaps should be available right away. The next step is to submit the sitemapindex to major search engines. You only need the sitemapindex and nothing else, those search engines will automatically recognize other included sitemaps. You can read a small How-to if you are interested." +msgstr "Apabila anda aktifkan plugin ini, semua pelan tapak sepatutnya sudah berada. Langkah seterusnya ialah dengan menghantar indeks pelan tapak kepada enjin carian. Anda cuma perlu indeks pelan tapak dan selain itu, enjin carian secara automatik mengenalpasti pelan tapak yang lain. Anda boleh merujuk Langkah-langkah jika anda berminat." + +#: includes/class-bwp-simple-gxs.php:349 +msgid "Output no more than" +msgstr "Output tidak lebih dari" + +#: includes/class-bwp-simple-gxs.php:350 +msgid "Default change frequency" +msgstr "Ubah frekuensi lalai" + +#: includes/class-bwp-simple-gxs.php:351 +msgid "Default priority" +msgstr "Keutamaan lalai" + +#: includes/class-bwp-simple-gxs.php:352 +msgid "Minimum priority" +msgstr "Keutamaan minimum" + +#: includes/class-bwp-simple-gxs.php:353 +msgid "Add sitemapindex to WordPress's virtual robots.txt?" +msgstr "Tambah indeks pelan tapak kepada WordPress's robots.txt?" + +#: includes/class-bwp-simple-gxs.php:354 +msgid "In sitemapindex, include" +msgstr "Di dalam indeks pelan tapak, termasuk" + +#: includes/class-bwp-simple-gxs.php:355 +msgid "Style your sitemaps with an XSLT stylesheet?" +msgstr "Ubah pelan tapak anda dengan gaya lembar XSLT?" + +#: includes/class-bwp-simple-gxs.php:356 +msgid "Custom XSLT stylesheet URL" +msgstr "URL gaya lembar XSLT yang diubah" + +#: includes/class-bwp-simple-gxs.php:357 +msgid "Show build stats in sitemaps?" +msgstr "Papar status bina dalam pelan tapak?" + +#: includes/class-bwp-simple-gxs.php:358 +msgid "Enable credit?" +msgstr "Paparkan penghargaan?" + +#: includes/class-bwp-simple-gxs.php:359 +msgid "Enable Gzip?" +msgstr "Benarkan Gzip?" + +#: includes/class-bwp-simple-gxs.php:360 +msgid "Module Options" +msgstr "Tetapan modul" + +#: includes/class-bwp-simple-gxs.php:361 +msgid "Alternate module directory" +msgstr "Direktori pengganti modul" + +#: includes/class-bwp-simple-gxs.php:362 +msgid "Get no more than" +msgstr "Dapat tidak lebih daripada" + +#: includes/class-bwp-simple-gxs.php:363 +msgid "Caching Options" +msgstr "Tetapan Caching" + +#: includes/class-bwp-simple-gxs.php:364 +msgid "Enable caching?" +msgstr "Benarkan caching?" + +#: includes/class-bwp-simple-gxs.php:365 +msgid "Enable auto cache re-generation?" +msgstr "Benarkan auto cache di-generasi?" + +#: includes/class-bwp-simple-gxs.php:366 +msgid "Cached sitemaps will last for" +msgstr "Pelan tapak yang di-cache-kan akan bertahan selama" + +#: includes/class-bwp-simple-gxs.php:367 +msgid "Cached sitemaps are stored in (auto detected)" +msgstr "Pelan tapak yang di-cache-kan akan disimpan di dalam (auto carian)" + +#: includes/class-bwp-simple-gxs.php:371 +msgid "Cache your sitemaps for better performance." +msgstr "Cache pelan tapak anda untuk prestasi yang memberangsangkan." + +#: includes/class-bwp-simple-gxs.php:372 +#, php-format +msgid "This plugin uses modules to build sitemap data so it is recommended that you extend this plugin using modules rather than hooks. Some of the settings below only affect modules extending the base module class. Read more about using modules here." +msgstr "Plugin ini menggunakan modul untuk membina data pelan tapak jadi digalakkan untuk anda mengembangkan plugin ini menggunakan modul-modul berbanding dikait. Salah satu daripada tetapan dibawah hanya mempengaruhi dalam memperluas kelas modul asas.Lebih lanjut tentang penggunaan modul disini." + +#: includes/class-bwp-simple-gxs.php:382 +#: includes/class-bwp-simple-gxs.php:388 +msgid "second(s)" +msgstr "saat" + +#: includes/class-bwp-simple-gxs.php:383 +#: includes/class-bwp-simple-gxs.php:389 +msgid "minute(s)" +msgstr "minit" + +#: includes/class-bwp-simple-gxs.php:384 +#: includes/class-bwp-simple-gxs.php:390 +msgid "hour(s)" +msgstr "jam" + +#: includes/class-bwp-simple-gxs.php:385 +#: includes/class-bwp-simple-gxs.php:391 +msgid "day(s)" +msgstr "hari" + +#: includes/class-bwp-simple-gxs.php:398 +#: includes/class-bwp-simple-gxs.php:399 +#: includes/class-bwp-simple-gxs.php:400 +msgid "read more" +msgstr "lebih lanjut" + +#: includes/class-bwp-simple-gxs.php:403 +msgid "your sitemaps are generated and then cached to reduce unnecessary work." +msgstr "pelan tapak anda telah dihasilkan dan kemudian di-cache-kan untuk mengurangkan kerja yang diperlukan." + +#: includes/class-bwp-simple-gxs.php:404 +msgid "when a cached sitemap expires, this plugin will try to generate the cache again. If you disable this, remember to manually flush the cache once in a while." +msgstr "apabila cache pelan tapak luput, plugin ini akan cuba untuk menghasilkan cache lagi. Jika anda tidak membenarkan ini, waspada untuk membuang cache secara manual sekali sekala." + +#: includes/class-bwp-simple-gxs.php:404 +msgid "Flush the cache" +msgstr "Buang cache" + +#: includes/class-bwp-simple-gxs.php:405 +msgid "tell you useful information such as build time, memory usage, SQL queries, etc." +msgstr "beritahu anda maklumat seperti masa bina, pengunaan memori, maklumat SQL dan lain-lain." + +#: includes/class-bwp-simple-gxs.php:406 +#, php-format +msgid "make your sitemaps ~ 70% smaller." +msgstr "membuat pelan tapak anda 70% lebih kecil." + +#: includes/class-bwp-simple-gxs.php:407 +msgid "static pages' sitemap." +msgstr "pelan tapak muka statik." + +#: includes/class-bwp-simple-gxs.php:408 +msgid "taxonomy archives' sitemaps, including custom taxonomies." +msgstr "menamakan arkib pelan tapak, termasuk yang diubahsuai." + +#: includes/class-bwp-simple-gxs.php:409 +msgid "tag archives' sitemaps." +msgstr "Lekat arkib pelan tapak." + +#: includes/class-bwp-simple-gxs.php:410 +msgid "date archives' sitemaps." +msgstr "tarikh arkib pelan tapak." + +#: includes/class-bwp-simple-gxs.php:411 +msgid "some copyrighted info is also added to your sitemaps. Thanks!" +msgstr "sedikit maklumat hakcipta juga akan ditambah pada pelan tapak anda. Terima kasih! " + +#: includes/class-bwp-simple-gxs.php:412 +msgid "This will load the default stylesheet provided by this plugin. You can set a custom stylesheet below or filter the bwp_gxs_xslt hook." +msgstr "Ini akan menambah gaya lembar lalai yang dibekalkan dengan plugin ini. Anda boleh menetapkan gaya lembar yang diubahsuai di bawah atau dengan menapis bwp_gxs_xslt." + +#: includes/class-bwp-simple-gxs.php:413 +#, php-format +msgid "If you're on a Multi-site installation with Sub-domain enabled, each site will have its own robots.txt, sites in sub-directory will not. Please read the documentation for more info." +msgstr "Jika anda di dalam Multi-tapak pemasangan dengan Sub-domain digunakan, setiap tapak akan ada setiap robot.txt sendiri, manakala tapak di dalam sub- direktori adalah sebaliknya. Sila rujuk dokumentasi untuk maklumat terperinci." + +#: includes/class-bwp-simple-gxs.php:416 +msgid "item(s) in one sitemap. Actually, 5000 would be more ideal. You can not go over 50,000, though." +msgstr "item di dalam satu pelan tapak. Akan tetapi, 5000 adalah lebih sesuai. Anda tidak boleh melebihi 50,000, walaubagaimanapun." + +#: includes/class-bwp-simple-gxs.php:417 +msgid "Input a full path to the directory where you put your own modules (e.g. /home/mysite/public_html/gxs-modules/), you can also override a built-in module by having a module with the same filename in this directory. A filter is also available if you would like to use PHP instead." +msgstr "Masuk ruang penuh untuk direktori dimana anda meletak modul anda sendiri (contoh /home/mysite/public_html/gxs-modules/), anda juga boleh melebih-naik modul yang terbina dengan mendapat nama modul fail yang sama di dalam direktori. Penapis juga tersedia jika anda mahu menggunakan PHP." + +#: includes/class-bwp-simple-gxs.php:418 +msgid "The cache directory must be writable (i.e. CHMOD to 755 or 777)." +msgstr "Cache direktori harus boleh ditulis (i.e. CHMOD to 755 or 777)." + +#: includes/class-bwp-simple-gxs.php:419 +msgid "item(s) in one SQL query. This helps you avoid running too heavy queries." +msgstr "item-item di dalam satu maklumat SQL. Ini membantu anda untuk menghindar dari menggunakan maklumat terlalu banyak." + +#: includes/class-bwp-simple-gxs.php:422 +msgid "expected to be an absolute URL, e.g. http://example.com/my-stylesheet.xsl. You must also have a style sheet for the sitemapindex that can be accessed through the above URL, e.g. my-stylesheet.xsl and my-stylesheetindex.xsl). Please leave blank if you do not wish to use." +msgstr "jangkaan untuk menjadi URL tetap, contohnya http://example.com/my-stylesheet.xsl. Anda juga harus mempunyai gaya lembar untuk indeks pelan tapak yang mana boleh di akses melalui URL di atas, contohnya my-stylesheet.xsl dan my-stylesheetindex.xsl). Sila tinggalkan kosong sekiranya anda tidak berhasrat untuk menggunakannya." + +#: includes/class-bwp-simple-gxs.php:449 +#: includes/class-bwp-simple-gxs.php:451 +msgid "Notice" +msgstr "Notis" + +#: includes/class-bwp-simple-gxs.php:449 +#, php-format +msgid "%d cached sitemaps have been flushed successfully!" +msgstr "%d pelan tapak yang di-cache-kan telah di buang!" + +#: includes/class-bwp-simple-gxs.php:451 +msgid "Could not delete any cached sitemaps. Please manually check the cache directory." +msgstr "Tidak boleh buang mana-mana pelan tapak yang telah di-cache-kan. Sila rujuk cache direktori secara manual." + +#: includes/class-bwp-simple-gxs.php:503 +msgid "Warning" +msgstr "Amaran" + +#: includes/class-bwp-simple-gxs.php:503 +msgid "Cache directory does not exist or is not writable. Please read more about directory permission here (Unix)." +msgstr "Direktori cache tidak wujud atau tidak boleh dibaca. Sila rujuk direktori berkenaan kebenaran disini (Unix)." + +#: includes/class-bwp-simple-gxs.php:557 +msgid "(Debug is on)" +msgstr "(Debug dibuka)" + +#: includes/class-bwp-simple-gxs.php:570 +msgid "BWP Google XML Sitemaps Error: " +msgstr "Google XML Pelan tapak BWP Ralat:" + +#: includes/class-bwp-simple-gxs.php:570 +msgid "BWP Google XML Sitemaps Error" +msgstr "Google XML Pelan tapak BWP Ralat" + +#: includes/class-bwp-simple-gxs.php:593 +#, php-format +msgid "Nothing here... yet! Try submitting your sitemapindex first!" +msgstr "Tiada disini...lagi! Cuba hantar indeks pelan tapak anda dahulu!" + +#: includes/class-bwp-simple-gxs.php:593 +msgid "No log yet!" +msgstr "Tiada log lagi!" + +#: includes/class-bwp-simple-gxs.php:603 +#, php-format +msgid "%s" +msgstr "%s" + +#: includes/class-bwp-simple-gxs.php:603 +#, php-format +msgid "%s has been successfully built on %s." +msgstr "%s telah berjaya dibina %s." + +#: includes/class-bwp-simple-gxs.php:613 +#: includes/class-bwp-simple-gxs.php:616 +msgid "M j, Y : H:i:s" +msgstr "M j, Y : H:i:s" + +#: includes/class-bwp-simple-gxs.php:836 +#, php-format +msgid "Requested module (%s) not found or not allowed." +msgstr "Modul yang diminta (%s) tidak dijumpai atau tidak dibenarkan." + +#: includes/class-bwp-simple-gxs.php:886 +#: includes/class-bwp-simple-gxs.php:906 +#, php-format +msgid "Loaded a custom sub-module file: %s." +msgstr "Lain-lain fail sub-modul telah dibekalkan: %s." + +#: includes/class-bwp-simple-gxs.php:895 +#, php-format +msgid "Mapped sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the requested sub-module instead." +msgstr "Fail sub-module yang dikategorikan: %s tidak terdapat di dalam kedua-dua lalai dan lain-lain direktori modul. Plugin sekarang akan cuba untuk menggunakan sub-modul." + +#: includes/class-bwp-simple-gxs.php:914 +#, php-format +msgid "Sub-module file: %s is not available in both default and custom module directory. The plugin will now try loading the parent module instead." +msgstr "Fail sub-modul: %s tidak terdapat di dalam kedua-dua lalai dan juga lain-lain direktori modul. Plugin akan cuba menggunakan modul utama." + +#: includes/class-bwp-simple-gxs.php:927 +#, php-format +msgid "Loaded a custom module file: %s." +msgstr "Menggunakan lain-lain fail modul: %s." + +#: includes/class-bwp-simple-gxs.php:933 +#, php-format +msgid "Could not load module file: %s in both default and custom module directory. Please recheck if that module file exists." +msgstr "Tidak boleh menggunakan fail modul: %s di kedua-dua lalai dan juga lain-lain direktori modul. Sila semak semula jika fail modul itu wujud." + +#: includes/class-bwp-simple-gxs.php:951 +#, php-format +msgid "There is no class named %s in the module file %s." +msgstr "Tiada kelas dinamakan %s di dalam fail modul %s." + +#: includes/class-bwp-simple-gxs.php:960 +#, php-format +msgid "Loaded a custom sitemapindex module file: %s." +msgstr "Menggunakan lain-lain fail modul indeks pelan tapak: %s." + +#: includes/class-bwp-simple-gxs.php:980 +#, php-format +msgid "Successfully generated %s.xml using module %s." +msgstr "Berjaya menghasilkan %s.xml menggunakan modul %s." + +#: includes/class-bwp-simple-gxs.php:1090 +#, php-format +msgid "Pinged %s successfully!" +msgstr "Penghantaran berjaya %s !" + +#: includes/class-bwp-simple-gxs.php:1096 +#, php-format +msgid "Ping limit for today to %s has been reached, sorry!" +msgstr "Had menghantar untuk hari ini kepada %s telah dicapai, maaf!" + +#: includes/class-bwp-simple-gxs.php:1124 +#, php-format +msgid "%s.xml does not have any item. The plugin has fired a 404 header to the search engine that requests it. You should check the module that generates that sitemap (%s.php)." +msgstr "%s.xml tiada apa-apa item. Plugin telah membuang permulaan 404 kepada enjian carian yang memintanya. Anda seharusnya meninjau modul yang menghasilkan pelan tapak itu (%s.php)." + +#: includes/bwp-option-page/includes/class-bwp-option-page.php:74 +msgid "Plugin Configurations" +msgstr "Tetapan Plugin" + +#: includes/bwp-option-page/includes/class-bwp-option-page.php:391 +msgid "Save Changes" +msgstr "Simpan Perubahan" + diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..638256f --- /dev/null +++ b/readme.txt @@ -0,0 +1,257 @@ +=== Better WordPress Google XML Sitemaps (with sitemapindex and Multi-site support) === +Contributors: OddOneOut +Donate link: http://betterwp.net/wordpress-plugins/google-xml-sitemaps/#contributions +Tags: xml sitemaps, xml sitemap, google xml sitemaps, sitemapindex, sitemap, sitemaps, seo, bing, google, msn, ask, multi-site, multisite +Requires at least: 3.0 +Tested up to: 3.3 +Stable tag: 1.1.6 + +The first WordPress XML Sitemap plugin that comes with comprehensive support for Sitemapindex and Multi-site. + +== Description == + +Welcome to the first WordPress sitemap plugin that has support for both sitemapindex and Multi-site websites! You will no longer have to worry about the 50,000 URL limit or the time it takes for a sitemap to be generated. This plugin is fast, consumes much fewer resources and can be extended via your very own modules (yes, no hooks needed!). Here's a [demo](http://betterwp.net/sitemapindex.xml) of the sitemapindex if you are interested. + +**New in 1.1.0!** + +* This plugin can now automatically split large post sitemaps into smaller ones. You can set a limit for each small sitemap. For example if you have 200K posts and would like to have 10K posts for each sitemap, BWP GXS will then split `post.xml` into 20 parts (i.e. from `post_part1.xml` to `post_part20.xml`). This helps you bypass the 50,000 URLs limit without having to build your custom modules, and also helps make your sitemaps smaller, lighter, and of course faster to generate. This plugin has been tested on sites that have nearly 200K posts and it took less than 1 second to generate the sitemapindex. +* Added a new sitemap, called External Pages' sitemap, using which you can easily add links to pages that do not belong to WordPress to the Sitemap Index. Please refer to the [customization section](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/#external_sitemap) for more details. +* Added options in the Generator to exclude certain post types, taxonomies without having to use filters. +* Added new hooks to default post-based and taxonomy-based modules to allow easier SQL query customization (you don't have to develop custom modules anymore just to change minor things). Read [here](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/#exclude_items) for more details. + +**Sitemapindex Support** + +What's so great about a sitemapindex you might say? Sitemapindex, as its name suggests, is one kind of sitemaps that allows you to group multiple sitemaps files inside it. Sitemapindex, therefore, gives you many benefits, such as: possibility to bypass the 50,000 URL limit (you can have 10 custom sitemaps, each has 10000 URLs), or possibility to make the generation time much faster (because each sitemap is requested separately and is built by its own module), etc. + +**Multi-site Support** + +Each website within your network will have its own sitemapindex and sitemaps. For sub-domain installation, your sitemapindex will appear at `http://sub-domain.example.com/sitemapindex.xml`. For sub-folder installation, your sitemapindex will appear at `http://example.com/sub-folder/sitemapindex.xml`. And of course, there's always a sitemapindex for your main site, available at `http://example.com/sitemapindex.xml`. If you choose the sub-domain approach, each sub-domain can also have its own robots.txt. + +**Custom sitemaps using modules** + +The unrivaled flexibility this plugin offers is the ability to define your custom sitemaps using modules. Each module is a actually .php file that tell BWP Google XML Sitemap how to build a sitemap file. You can extend default modules or create completely new ones. This plugin also comes with a convenient base class for developing modules with easy to use and thoroughly documented API. Since modules can be defined by you, there's no limitation what a sitemap can have (for example you can bypass the 50,000 URL limit, as stated above). There's one limitation, though: your imagination ;) . Oh, did I mention that you can even use module to create another sitemapindex? + +**Detailed Log and Debugging mode** + +Developing modules needs debugging and this plugin makes that so easy for any developers. There are two kinds of logs: sitemap log and build log. Sitemap log tells you what sitemaps you have and when they were last requested/updated while build log tells you what's going on when a particular sitemap is built. The debug mode helps you trace errors in modules conveniently! + +**For a complete feature list, please visit this [plugin's official page](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/)** + +**Important Notes** + +If you have any problem using this plugin, refer to the [FAQ section](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/faq/) for possible solutions, and workarounds. + +**Get in touch** + +* I'm available at [BetterWP.net](http://betterwp.net) and you can also follow me on [Twitter](http://twitter.com/0dd0ne0ut). +* Check out [latest WordPress Tips and Ideas](http://feeds.feedburner.com/BetterWPnet) from BetterWP.net. + +**Languages** + +* English (default) +* Malaysian (ms_MY) - Thanks to [d4rkcry3r](http://d4rkcry3r.com)! + +Please [help translate](http://betterwp.net/wordpress-tips/create-pot-file-using-poedit/) this plugin! + +== Installation == + +1. Upload the `bwp-google-xml-sitemaps` folder to the `/wp-content/plugins/` directory +2. Activate the plugin through the Plugins menu in WordPress. After activation, you should see a menu of this plugin on your left. If you can not locate it, click on Settings under the plugin's name. +3. Configure the plugin +4. Build your sitemap for the first time or just submit the sitemapindex to all major search engines. +5. Enjoy! + +[View instructions with images](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/installation/). + +== Frequently Asked Questions == + +**Q1: I got white pages and/or 'Content Encoding Error' error?** + +1. PHP error messages from other plugins or from this plugin itself can cause this issue, especially when you have `WP_DEBUG` set to true (try commenting out this line in your `wp-config.php` file: `define(WP_DEBUG, true);`). Refer to the second question to know how to trace the actual errors. + +2. BWP GXS runs out of memory or reaches maximum execution time. This often happens when you try to build large sitemaps. I've tried to optimize this plugin a lot since the first version, but if you are using a lot of memory eating plugins on your website, it is very hard for BWP GXS to build huge sitemaps (containing thousands of items). Anyway, to resolve this issue, try decreasing the three limit options in the Generator tab: max number of items per sitemap (first option), max number of items per split sitemap (first option in Sitemap Index Options) and max items to get in one SQL query (second option in Module Options). You might try the following presets (in the same order as above): + * 1000, 1000, 100 (for sites with low memory limit like 32MB) + * 5000, 5000, 500 (for sites with lots of posts, tags, categories, etc.) + * 5000, 5000, 2500 (if you have problem with max execution time) + + Also, you can try the tips mentioned in [this post of mine](http://betterwp.net/6-wordpress-memory-usage/). + +3. A caching plugin is interfering. Tell that caching plugin to ignore `.xml` file. For example, if you use WP Super Cache, on the Advanced Tab, scroll to the 'Accepted Filenames & Rejected URIs' section, and then in the first textarea, type in `\.xml`. Now save the changes and flush the all caches. See if that works for you. + +**Q2: I've tried the tips mentioned in Question #1, but still got white pages / plain text sitemaps?** + +It's very likely that you're enabling this option: 'Clean unexpected output before sitemap generation', try disabling it and your sitemaps will show up as expected. + +**Q3: I got the error 'Content Encoding Error', what should I do?** + +If you are enabling this plugin's debug mode and/or WP_DEBUG, this error is very normal because the module you use might print errors on pages, thus corrupting your xml sitemaps. To view the actual errors without being greeted with the 'Content Encoding Error', please follow these steps: + +1. Enable this plugin's debug mode if you haven't done so. +2. Open the file `class-bwp-simple-gxs.php` inside `bwp-google-xml-sitemaps/includes/` and look for this function: `output_sitemap()`. +3. Place an `exit;` right after the opening bracket, like so: +
    
    +function output_sitemap()
    +{
    +	exit;
    +
    +4. Refresh the sitemaps with problems. +5. Kindly report the errors you see by commenting or through the [contact form](http://betterwp.net/contact/). Thanks! + +Note that, however, some error messages will never show up. In such case, you might want to locate the `error_log` file within your WordPress installation's root directory and read its contents for the error messages. + +**Q4: I got an 'Error loading stylesheet' error, what should I do?** + +As of version 1.1.0 it is almost impossible for such error to show up, but if you set the site url and the home url differently (one with `www` and one isn't), you will see this error. Just choose to disable stylesheet in Generator tab or change your site / home URL settings. + +**Q5: I got a HTTP parse error when I submit sitemap to Google Webmaster Tools, what should I do?** + +Please first see the answer to the first question, if it didn't work, and you are using a cache plugin such as W3 Total Cache, it is possible that such plugin wrongly assigns HTTP status headers to my sitemaps. + +For example, in W3 Total Cache 0.9.2.2 or possibly older, go to **Performance -> Browser Cache**, and then go to '404 error exception list' in the 'General' option block, and find this line: + +
    sitemap(_index|[0-9]+)?\.xml(\.gz)?
    + +OR this line: + +
    sitemap\.xml(\.gz)?
    + +and change it to: + +
    (sitemapindex|[a-z0-9_-]+)\.xml
    + +Save the changes and then tell W3TC to auto-install the rewrite rules to your `.htaccess` file. + +BWP GXS's sitemaps will now have correct HTTP status headers. + +**Q6: When I visit `http://example.com/sitemapindex.xml` , WordPress returns a 404 page. What should I do?** + +This might be caused by unflushed rewrite rules, which should have been flushed when you activate this plugin. You can try flushing them manually by visiting Settings -> Permalinks and then clicking Save Changes. + +**Q7: When I visit any sitemap, a plain (no theme) 404 error page appears, what's the problem?** + +You are possibly using some caching plugins that redirect all non-existent pages to 404 error page. Sitemaps produced by this plugin are virtual sitemaps so they will all be redirected. Just open the .htaccess file and change the `sitemap\.xml` part to something like `[a-z0-9-_]+\.xml` and you're fine. + +**Q8: I choose not to display certain sitemaps but the sitemapindex still displays the them?** + +What you see is actually a cached version of the sitemapindex. You can wait for it to be refreshed automatically or simply choose to 'Flush the Cache'. + +**Q9: BWP GXS tells me that 'Requested module not found or not allowed', what should I do?** + +This depends on specific situations and your current settings. Basically this means that the module you're trying to access has not been registered with BWP GXS or that module has been disabled but the cached sitemapindex still displays it (which is related to the question above). For a list of default modules (or sitemaps), please read this section. + +**Q10: Is there anyway to rename sitemapindex.xml to sitemap.xml?** + +You don't have to. A visit to `http://example.com/sitemap.xml` will show you the same sitemapindex. This is done to make BWP GXS more compatible with blogs that have lots of real `robots.txt`. Please note that you must remove any real sitemap.xml file in your website's root for this feature to work. + +**Q11: The custom sitemapindex I create seems to be nested inside the default sitemapindex, is that a bug or something?** + +That's the default behaviour of this plugin and I plan to improve it in future versions. Don't worry, though, you might see a red X next to your sitemapindex's name in Google's Webmaster Tools but that's only because you haven't submitted your custom sitemapindex. If you submit it separately, the error will go away :). + +[Check plugin news and ask questions](http://betterwp.net/topic/google-xml-sitemaps/). + +== Screenshots == + +1. A sample Sitemap Index this plugin produces. Large post-based sitemap was split into two parts. +2. A Custom Post Type Sitemap +3. An External Pages' Sitemap +4. The Configuration Page + +== Changelog == + += 1.1.6 = +* Temporary fix for 1.1.5's broken custom post type URL issue. Expect a 1.1.7 real soon. + += 1.1.5 = +* Added a new 'site.xml' sitemap that lists all blogs within your site / network. +* Added a new 'author.xml' sitemap that lists all authors contributing to a blog. +* BWP GXS should now show the correct mapped sitemap URLs in the Statistics tab if you use WPMU Domain Mapping plugin. +* Fixed a bug that causes duplicate items to appear on sitemap parts, thanks to Aahan for reporting! +* Fixed a bug that causes the `post` post type sitemaps to show up even when disabled. + +**Note that the site sitemap will be enabled, while the author sitemap will be disabled by default.** + += 1.1.4 = +* Changed some options' descriptions. +* Fixed a possible incompatibility issue with FeedWordPress plugin and Suffusion theme. +* Other minor bug fixes. + += 1.1.3 = +* Gzip is now off by default as it was causing issue on some hosts. +* In previous versions, this plugin automatically cleaned unexpected outputs before sitemap generation so that sitemaps are generated properly. Such feature also causes issues on certain hosts. As of 1.1.3 this is an option in Generator tab, and it is enabled by default. +* Fixed a possible bug in the taxonomy module that could cause a maximum execution time error. Thanks to David Killingsworth for reporting this bug! +* Other minor bug fixes and improvements. + += 1.1.2 = +* Fixed a possible memory leak. +* Clear PHP errors in a friendlier way. +* Other minor bug fixes and improvements. + += 1.1.1 = +* Added an option for users to choose whether to use GMT for Last Modified time or not. +* Improved the taxonomy module a bit. +* Fixed a minor bug in the page module. +* Fixed a bug that affects rewrite rules of custom post types and taxonomies in some cases. A big thanks to crowinck! +* Other minor bug fixes and improvements. + += 1.1.0 = + +**New Features:** + +* This plugin can now automatically split large post sitemaps into smaller ones. You can set a limit for each small sitemap. For example if you have 200K posts and would like to have 10K posts for each sitemap, BWP GXS will then split `post.xml` into 20 parts (i.e. from `post_part1.xml` to `post_part20.xml`). This helps you bypass the 50,000 URLs limit without having to build your custom modules, and also helps make your sitemaps smaller, lighter, and of course faster to generate. This plugin has been tested on sites that have nearly 200K posts and it took less than 1 second to generate the sitemapindex. +* Added a new sitemap, called External Pages' sitemap, using which you can easily add links to pages that do not belong to WordPress to the Sitemap Index. Please refer to the [customization section](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/#external_sitemap) for more details. +* Added options in the Generator to exclude certain post types, taxonomies without having to use filters. +* Added new hooks to default post-based and taxonomy-based modules to allow easier SQL query customization (you don't have to develop custom modules anymore just to change minor things). Read [here](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/#exclude_items) for more details. + +**Improvements:** + +* Major overhaul of all modules to make them faster, more efficient, more accurate, and of course, consume much less memory. This version should eliminate most white page problems happened in previous versions. +* Improved compatibility with cache plugins. +* Improved support for sites that uses `%category%` in permalink structure. +* The plugin should now display style sheet correctly in tight situations. +* Added a clear log button to clear redundant log (available to network admin only). +* Added an option to include links to all sitemapindex.xml files in your network in the primary website's `robots.txt`. +* Tag archive sitemap can now be disabled properly. +* Fixed permalinks for people using index.php in permalink structure. +* Other minor bug fixes and improvements. + +For a detailed description of each new feature, please refer to the [release announcement](http://betterwp.net/257-bwp-google-xml-sitemaps-1-1-0/). + +**Due to major changes in core it is suggested that you clear the logs using the new 'Clear All Logs' button and double-check the Generator's settings. Have fun and please [rate this plugin](http://wordpress.org/extend/plugins/bwp-google-xml-sitemaps/) 5 stars if you like it, thanks!** + += 1.0.5 = +* Unregistered modules (such as redundant modules from 1.0.3) will now have a 404 HTTP status to prevent search engines from requesting them again. +* Time for each log will now make use of your current timezone setting in Settings -> General. +* And other minor fixes. + +**Thanks everyone for using this plugin!** + += 1.0.4 = +* Hot fix for WordPress in other languages, such as French, Russian. Prior to this version this plugin tries to use posts' and taxonomies' labels to build sitemaps' URLs in plural forms (e.g. taxonomy_categories). Unfortunately this breaks sitemaps when labels contain UTF8 characters with marks (such as catégories). All sitemaps now have singular forms. Hope that we will have a better solution in the future. + +**This change will make all logs' contents change as well. To remove redundant logs, please deactivate this plugin and then reactivate it.** + += 1.0.3 = +* Fixed incorrect regex for rewrite rules. +* Added a check to make sure all necessary rewrite rules are added. No need to manually flush rewrite rules anymore. +* `bwp_gxs_add_rewrite_rules` action now becomes `bwp_gxs_rewrite_rules` filter (the hook used to add your own sitemaps). + +**For people using a cache plugin, please visit the [FAQ section](http://betterwp.net/wordpress-plugins/google-xml-sitemaps/faq/) for a possible compatibility fix.** + += 1.0.2 = +* Fixed a bug that could produce wrong or empty last modified dates in sitemapindex. +* Corrected a typo in page.php module. +* Added Malaysian translation, thanks to d4rkcry3r! + += 1.0.1 = +* Now you can browser to `http://example.com/sitemap.xml` to view your sitemapindex. You can submit it too if you want. **Important**: Make sure you don't have any real sitemap.xml file in your website's root. Also, you will have to flush all rewrite rules, by either deactivating and then reactivating this plugin, or simply go to [Permalink Settings](http://example.com/wp-admin/options-permalink.php) and click on Save Changes. +* Build stats (build time, number of queries, memory usage) should be more accurate now. +* Add a canonical redirection for sitemap URL to avoid problems with XSLT style sheet's absolute URL. +* Fixed a minor error in the base module class. + += 1.0.0 = +* Initial Release. + +== Upgrade Notice == + += 1.0.0 = +* Enjoy the plugin! \ No newline at end of file diff --git a/screenshot-1.gif b/screenshot-1.gif new file mode 100644 index 0000000..3ee9d28 Binary files /dev/null and b/screenshot-1.gif differ diff --git a/screenshot-2.gif b/screenshot-2.gif new file mode 100644 index 0000000..02932a5 Binary files /dev/null and b/screenshot-2.gif differ diff --git a/screenshot-3.gif b/screenshot-3.gif new file mode 100644 index 0000000..e00e1f2 Binary files /dev/null and b/screenshot-3.gif differ diff --git a/screenshot-4.gif b/screenshot-4.gif new file mode 100644 index 0000000..474254b Binary files /dev/null and b/screenshot-4.gif differ diff --git a/xsl/bwp-sitemap.xsl b/xsl/bwp-sitemap.xsl new file mode 100644 index 0000000..4da6608 --- /dev/null +++ b/xsl/bwp-sitemap.xsl @@ -0,0 +1,99 @@ + + + + + + + XML Sitemap + + + + +

    XML Sitemap

    + +
    + + + + + + + + + + + odd + + + + + + + +
    LocationPriorityChange FrequencyLast Modified (GMT)
    + + + + + + + + + + + + +
    +
    + + + +
    +
    \ No newline at end of file diff --git a/xsl/bwp-sitemapindex.xsl b/xsl/bwp-sitemapindex.xsl new file mode 100644 index 0000000..eca3b0a --- /dev/null +++ b/xsl/bwp-sitemapindex.xsl @@ -0,0 +1,90 @@ + + + + + + + XML Sitemap Index + + + + +

    XML Sitemap Index

    + +
    + + + + + + + + + odd + + + + + +
    LocationLast Modified (GMT)
    + + + + + + + + +
    +
    + + + +
    +
    \ No newline at end of file