• Welcome to the Chevereto User Community!

    Here, users from all over the world come together to learn, share, and collaborate on everything related to Chevereto. It's a place to exchange ideas, ask questions, and help improve the software.

    Please keep in mind:

    • This community is user-driven. Always be polite and respectful to others.
    • Support development by purchasing a Chevereto license, which also gives you priority support.
    • Go further by joining the Community Subscription for even faster response times and to help sustain this space
  • Chevereto Support CLST

    Support response

    Support checklist

    • Got a Something went wrong message? Read this guide and provide the actual error. Do not skip this.
    • Confirm that the server meets the System Requirements
    • Check for any available Hotfix - your issue could be already reported/fixed
    • Read documentation - It will be required to Debug and understand Errors for a faster support response

[Addon] Sitemap

evilmoe2

Not needed
Hello,

I would like to share my sitemap script with you.
My script creates for everey of you categorie a own sitemap xml + a unsorted for everey image without a category.

This script just need 2 files (1 route + 1 template).

I`m using only external storage, you may have to do few changes to this script (from line 82).

Route (upload to app/routes/route.createSitemap.php)
PHP:
<?php
$route = function($handler) {
    try {
    //var_dump($handler);
  
    $sitemapsFolder = "sitemaps/";
    $absSitemapsFolder = getcwd()."/".$sitemapsFolder;
    $last_pictures   = 50000; // 50k is maximum  https://support.google.com/webmasters/answer/183668?hl=en
    $handler::$vars['sitemapsFolder'] = $sitemapsFolder;
    /////////////////////////////////////////////////////////////////////
    // Basic things
    if( !file_exists($absSitemapsFolder)){
      if(!mkdir($absSitemapsFolder))
        throw new Exception("Can not create ".$sitemapsFolder);
      
       if(!is_readable($absSitemapsFolder) or !is_writeable($absSitemapsFolder))
         throw new Exception("Can not read/write to ".$sitemapsFolder. ". Check permissions.");
    }
    // lastmod
    $objDateTime  =  new DateTime('NOW');
    $dateTime     = $objDateTime->format(DATE_W3C);

    /////////////////////////////////////////////////////////////////////
    // Get categories
    $categories = CHV\DB::queryFetchAll("SELECT category_id, category_name, category_url_key FROM chv_categories");

    // Add unsorted
    $categories[] = array("category_id" => null, "category_name" => "unsorted", "category_url_key" => "unsorted");
    $handler::$vars['categories'] = $categories;

    /////////////////////////////////////////////////////////////////////
    // Create index sitemap on root dir
    $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><sitemapindex />');
    $xml->addAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
    $xml->addAttribute('xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1', 'http://www.w3.org/2001/XMLSchema-instance');


    foreach($categories as $child) {
      $c = $xml->addChild("sitemap");
  
      $xml_url    = $handler->base_url.$sitemapsFolder.$child["category_url_key"].".xml";
      $xml_local  = $sitemapsFolder.$child["category_url_key"].".xml";
  
      $c->addChild("loc", $xml_url);
      $c->addChild("lastmod", $dateTime );
  
  
      /////////////////////////////////////////////////////////////////////
      // Lets create a sitemap for every category
      $xml2 = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset />');
      $xml2->addAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
      $xml2->addAttribute('xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1', 'http://www.w3.org/2001/XMLSchema-instance');
  
      $DB = CHV\DB::getInstance();
  
      if($child["category_name"] == "unsorted"){
    
        $q = $DB->query("SELECT image_id, image_title, image_nsfw, DATE_FORMAT(image_date_gmt, '%Y') as year, DATE_FORMAT(image_date_gmt, '%m') as month, DATE_FORMAT(image_date_gmt, '%d') as day, image_storage_mode, image_date_gmt, image_name, image_extension, storage_url FROM chv_images
                          LEFT JOIN chv_storages on storage_id = image_storage_id
                          WHERE image_category_id IS NULL
                          ORDER BY image_date_gmt DESC LIMIT :limit");
    
      } else {
    
        $q = $DB->query("SELECT image_id, image_title, image_nsfw, image_album_id, DATE_FORMAT(image_date_gmt, '%Y') as year, DATE_FORMAT(image_date_gmt, '%m') as month, DATE_FORMAT(image_date_gmt, '%d') as day, image_storage_mode, image_date_gmt, image_name, image_extension, storage_url FROM chv_images
                          LEFT JOIN chv_storages on storage_id = image_storage_id
                          WHERE image_category_id = :category
                          ORDER BY image_date_gmt DESC LIMIT :limit");
  
        $DB->bind(":category", $child["category_id"]);
      }
  
      $DB->bind(":limit", $last_pictures);
      $images = $DB->fetchAll();


      foreach($images as $image){
        //var_dump($image);
        $folder = "";
    
        switch ($image["image_storage_mode"]){
          case "datefolder":
            $folder = $image["year"]."/".$image["month"]."/".$image["day"]."/";
          break;
      
          default:
            $folder = "";
          break;
        }
        // Every image get his own URL
        $cc = $xml2->addChild("url");
        $cc->addChild("loc", $handler->base_url."image/".CHV\encodeID($image["image_id"], "encode") );

        $cc_image = $cc->addChild("xmlns:image:image");
        $cc_image->addChild("xmlns:image:title", $image["image_title"]);
        if($image["image_nsfw"] == 0){
          $cc_image->addChild("xmlns:image:family_friendly", "yes");
        } else {
          $cc_image->addChild("xmlns:image:family_friendly", "no");
        }
        $cc_image->addChild("xmlns:image:loc", $image["storage_url"].$folder.$image["image_name"].".".$image["image_extension"]);
      }
  
  
      $dom = new DomDocument();
      $dom->loadXML($xml2->asXML());
      $dom->formatOutput = true;

      file_put_contents( $xml_local, $dom->saveXML(), LOCK_EX);
      //
    }

    $dom = new DomDocument();
    $dom->loadXML($xml->asXML());
    $dom->formatOutput = true;


    if(file_put_contents($sitemapsFolder."sitemap.xml", $dom->saveXML(), LOCK_EX) === false){
      die("Could not write sitemap.xml");
    }



    } catch(Exception $e) {    
        G\exception_to_error($e);
    }
};

?>


Template (upload to app/themes/Peafowl/views/createSitemap.php)
HTML:
<?php if(!defined('access') or !access) die('This file cannot be directly accessed.'); ?>
<?php G\Render\include_theme_header(); ?>

<div class="content-width">
    <div class="page-not-found">
        <h1>Sitemap</h1>
        <h4><a href="<?php echo G\get_base_url()."/".get_sitemapsFolder()."sitemap.xml";?>">Sitemap index</a></h4>
    
        <p>Sitemaps created for:</p>
      <div>
        <ul>
        <?php
          $cat = get_categories();
          foreach($cat as $id => $key){
            echo "<li>".$key["category_name"]." = <a href=\"".G\get_base_url()."/".get_sitemapsFolder().$key["category_name"].".xml"."\">".$key["category_name"].".xml</a></li>";
          }
        ?>
        </ul>
      </div>
  </div>
</div>

<?php G\Render\include_theme_footer(); ?>

<?php if(isset($_REQUEST["deleted"])) { ?>
<script>PF.fn.growl.call("<?php echo (G\get_route_name() == 'user' ? _s('The user has been deleted') : _s('The content has been deleted.')); ?>"); </script>
<?php } ?>


Thats its. You just need a cron which runs your route script for example every hour.
Command: crontab -e
Code:
1 * * * *      wget -O /dev/null -o /dev/null https://www.domain.tld/createSitemap

Or use a website like https://www.setcronjob.com/


Todo:
  • Private images should not be in a sitemap
 
Last edited:
Code:
Warning: DOMDocument::loadXML(): redefinition of the xmlns prefix is forbidden in Entity, line: 2 in /home/app/routes/route.createSitemap.php on line 114

Chevereto error: Internal Server Error

getting error while generating sitemap
 
I get the error:

This page contains the following errors:
error on line 2 at column 1: Extra content at the end of the document
Below is a rendering of the page up to the first error.
 
Do you use a external storage?

I think this query is the problem in your case:


Code:
 $q = $DB->query("SELECT image_id, image_title, image_nsfw, DATE_FORMAT(image_date_gmt, '%Y') as year, DATE_FORMAT(image_date_gmt, '%m') as month, DATE_FORMAT(image_date_gmt, '%d') as day, image_storage_mode, image_date_gmt, image_name, image_extension, storage_url FROM chv_images
                          LEFT JOIN chv_storages on storage_id = image_storage_id
                          WHERE image_category_id IS NULL
                          ORDER BY image_date_gmt DESC LIMIT :limit");
 
Yes i use external storage (OVH andGoogle), i have already used your script and its working perfectly, but since recent update in Chevereto, its not working.
 
I think your have some invalid chars in your title which are included in xml.

Code:
$cc_image->addChild("xmlns:image:title", $image["image_title"]);

See here: http://stackoverflow.com/questions/8401222/how-to-validate-cdata-section-for-an-xml-in-php

Code:
/**
* Removes invalid characters from an HTML string
*
* @param string $content
*
* @return string
*/
function sanitize_html($content) {
  if (!$content) return '';
  $invalid_characters = '/[^\x9\xa\x20-\xD7FF\xE000-\xFFFD]/';
  return preg_replace($invalid_characters, '', $content);
}


Add this function and replace the line for the title with this.

Code:
$cc_image->addChild("xmlns:image:title", APP\sanitize_html($image["image_title"]));
 
Thanks, i have sent you private message. I have error with your code.
 
replace all

Code:
$image["image_title"]

with

Code:
G\safe_html($image["image_title"])
 
Back
Top