├── LICENSE.txt ├── README.md ├── composer.json └── src ├── Watson └── Sitemap │ ├── Facades │ └── Sitemap.php │ ├── Sitemap.php │ ├── SitemapServiceProvider.php │ └── Tags │ ├── BaseTag.php │ ├── ChangeFrequency.php │ ├── ExpiredTag.php │ ├── ImageTag.php │ ├── MultilingualTag.php │ ├── Sitemap.php │ ├── Tag.php │ └── Video │ ├── VideoPlatformTag.php │ ├── VideoPriceTag.php │ ├── VideoRestrictionTag.php │ └── VideoTag.php ├── config └── config.php └── views ├── sitemap.php └── sitemaps.php /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Dwight Watson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sitemap for Laravel 2 | =================== 3 | 4 | [![Build Status](https://travis-ci.org/dwightwatson/sitemap.png?branch=master)](https://travis-ci.org/dwightwatson/sitemap) 5 | [![Total Downloads](https://poser.pugx.org/watson/sitemap/downloads.svg)](https://packagist.org/packages/watson/sitemap) 6 | [![Latest Stable Version](https://poser.pugx.org/watson/sitemap/v/stable.svg)](https://packagist.org/packages/watson/sitemap) 7 | [![Latest Unstable Version](https://poser.pugx.org/watson/sitemap/v/unstable.svg)](https://packagist.org/packages/watson/sitemap) 8 | [![License](https://poser.pugx.org/watson/sitemap/license.svg)](https://packagist.org/packages/watson/sitemap) 9 | 10 | 11 | Sitemap is a package built specifically for Laravel that will help you generate XML sitemaps for Google. Based on [laravel-sitemap](https://github.com/RoumenDamianoff/laravel-sitemap) this package operates in a slightly different way to better fit the needs of our project. A facade is used to access the sitemap class and we have added the ability to produce sitemap indexes as well as sitemaps. Furthermore, it's tested. 12 | 13 | Read more about sitemaps and how to use them efficiently on [Google Webmaster Tools](https://support.google.com/webmasters/answer/156184?hl=en). 14 | 15 | ## Installation 16 | 17 | ```sh 18 | composer require watson/sitemap 19 | ``` 20 | 21 | ## Usage 22 | 23 | ### Creating sitemap indexes 24 | If you have a large number of links (50,000+) you will want to break your sitemaps out into seperate sitemaps with a sitemap index linking them all. You add sitemap indexes using `Sitemap::addSitemap($location, $lastModified)` and then you return the sitemap index with `Sitemap::renderSitemapIndex()`. The `$lastModified` variable will be parsed and converted to the right format for a sitemap. 25 | 26 | Here is an example controller that produces a sitemap index. 27 | 28 | ```php 29 | namespace App\Http\Controllers; 30 | 31 | use Sitemap; 32 | 33 | class SitemapsController extends Controller 34 | { 35 | public function index() 36 | { 37 | // Get a general sitemap. 38 | Sitemap::addSitemap('/sitemaps/general'); 39 | 40 | // You can use the route helpers too. 41 | Sitemap::addSitemap(route('sitemaps.posts')); 42 | 43 | // Return the sitemap to the client. 44 | return Sitemap::index(); 45 | } 46 | } 47 | ``` 48 | 49 | Simply route to this as you usually would, `Route::get('sitemap', 'SitemapsController@index');`. 50 | 51 | ### Creating sitemaps 52 | Similarly to sitemap indexes, you just add tags for each item in your sitemap using `Sitemap::addTag($location, $lastModified, $changeFrequency, $priority)`. You can return the sitemap with `Sitemap::renderSitemap()`. Again, the `$lastModified` variable will be parsed and convered to the right format for the sitemap. 53 | 54 | If you'd like to just get the raw XML, simply call `Sitemap::xml()`. 55 | 56 | Here is an example controller that produces a sitemap for blog posts. 57 | 58 | ```php 59 | namespace App\Http\Controllers; 60 | 61 | use Post; 62 | use Sitemap; 63 | 64 | class SitemapsController extends Controller 65 | { 66 | public function posts() 67 | { 68 | $posts = Post::all(); 69 | 70 | foreach ($posts as $post) { 71 | Sitemap::addTag(route('posts.show', $post), $post->updated_at, 'daily', '0.8'); 72 | } 73 | 74 | return Sitemap::render(); 75 | } 76 | } 77 | ``` 78 | 79 | If you just want to pass a model's `updated_at` timestamp as the last modified parameter, you can simply pass the model as the second parameter and the sitemap will use that attribute automatically. 80 | 81 | **If you're pulling a lot of records from your database you might want to consider restricting the amount of data you're getting by using the `select()` method. You can also use the `chunk()` method to only load a certain number of records at any one time as to not run out of memory.** 82 | 83 | ### Image sitemaps 84 | You can use Google image extensions for sitemaps to give Google more information about the images available on your pages. [Read the specification](https://support.google.com/webmasters/answer/178636?hl=en) 85 | 86 | Images are associated with page and you can use up to 1000 images per page. 87 | 88 | Here is an example of adding image tag to usual page tag. 89 | 90 | ```php 91 | namespace App\Http\Controllers; 92 | 93 | use Page; 94 | use Sitemap; 95 | 96 | class SitemapsController extends Controller 97 | { 98 | public function pages() 99 | { 100 | $pages = Page::all(); 101 | 102 | foreach ($pages as $page) { 103 | $tag = Sitemap::addTag(route('pages.show', $page), $page->updated_at, 'daily', '0.8'); 104 | 105 | foreach ($page->images as $image) { 106 | $tag->addImage($image->url, $image->caption); 107 | } 108 | } 109 | 110 | return Sitemap::render(); 111 | } 112 | } 113 | ``` 114 | 115 | Here is the full list of arguments to add an image to a tag. 116 | 117 | ```php 118 | $tag->addImage($location, $caption, $geoLocation, $title, $licenceUrl); 119 | ``` 120 | 121 | ## Configuration 122 | 123 | To publish the configuration file for the sitemap package, simply run this Artisan command: 124 | 125 | ```sh 126 | php artisan config:publish watson/sitemap 127 | 128 | php artisan vendor:publish --provider="Watson\Sitemap\SitemapServiceProvider" 129 | ``` 130 | 131 | Then take a look in `config/sitemap.php` to see what is available. 132 | 133 | ### Caching 134 | 135 | By default, caching is disabled. If you would like to enable caching, simply set `cache_enabled` in the configuration file to `true`. You can then specify how long you would like your views to be cached for. Keep in mind that when enabled, caching will affect each and every request made to the sitemap package. 136 | 137 | ### Multilingual tags 138 | 139 | If you'd like to use a mutlilingual tag, simply pass an instance of one to the `addTag` method. Below is a crude example of how you would pass alternate tag locations for different languages. 140 | 141 | ```php 142 | Sitemap::addTag(new \Watson\Sitemap\Tags\MultilingualTag( 143 | $location, 144 | $lastModified, 145 | $changeFrequency, 146 | $priority, 147 | [ 148 | 'en' => $location . '?lang=en', 149 | 'fr' => $location . '?lang=fr' 150 | ] 151 | )); 152 | ``` 153 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "watson/sitemap", 3 | "description": "Generate Google Sitemaps in Laravel", 4 | "keywords": [ 5 | "laravel", 6 | "sitemaps" 7 | ], 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Dwight Watson", 12 | "email": "dwightwatson@studious.com.au" 13 | } 14 | ], 15 | "require": { 16 | "php": "^8.0", 17 | "illuminate/http": "^8.0|^9.0|^10.0|^11.0|^12.0", 18 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^9.0|^10.5", 22 | "mockery/mockery": "^1.3.1" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Watson\\": "src/Watson" 27 | } 28 | }, 29 | "extra": { 30 | "laravel": { 31 | "providers": [ 32 | "Watson\\Sitemap\\SitemapServiceProvider" 33 | ], 34 | "aliases": { 35 | "Sitemap": "Watson\\Sitemap\\Facades\\Sitemap" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Facades/Sitemap.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 56 | $this->request = $request; 57 | } 58 | 59 | /** 60 | * Add new sitemap to the sitemaps index. 61 | * 62 | * @param \Watson\Sitemap\Tags\Sitemap|string $location 63 | * @param \DateTimeInterface|string|null $lastModified 64 | * @return void 65 | */ 66 | public function addSitemap($location, $lastModified = null) 67 | { 68 | $sitemap = $location instanceof SitemapTag ? $location : new SitemapTag($location, $lastModified); 69 | 70 | $this->sitemaps[] = $sitemap; 71 | } 72 | 73 | /** 74 | * Retrieve the array of sitemaps. 75 | * 76 | * @return SitemapTag[] 77 | */ 78 | public function getSitemaps() 79 | { 80 | return $this->sitemaps; 81 | } 82 | 83 | /** 84 | * Render an index of sitemaps. 85 | * 86 | * @return \Illuminate\Http\Response 87 | */ 88 | public function index() 89 | { 90 | if ($cachedView = $this->getCachedView()) { 91 | return response()->make($cachedView, 200, ['Content-type' => 'text/xml']); 92 | } 93 | 94 | $sitemapIndex = response()->view('sitemap::sitemaps', ['__sitemaps' => $this->getSitemaps()], 200, ['Content-type' => 'text/xml']); 95 | 96 | $this->saveCachedView($sitemapIndex); 97 | 98 | return $sitemapIndex; 99 | } 100 | 101 | /** 102 | * Render an index of sitemaps. 103 | * 104 | * @return \Illuminate\Http\Response 105 | */ 106 | public function renderSitemapIndex() 107 | { 108 | return $this->index(); 109 | } 110 | 111 | /** 112 | * Add a new sitemap tag to the sitemap. 113 | * 114 | * @param \Watson\Sitemap\Tags\Tag|string $location 115 | * @param \DateTimeInterface|string|null $lastModified 116 | * @param string|null $changeFrequency 117 | * @param string|null $priority 118 | * @return \Watson\Sitemap\Tags\Tag 119 | */ 120 | public function addTag($location, $lastModified = null, $changeFrequency = null, $priority = null) 121 | { 122 | $tag = $location instanceof Tag ? $location : new Tag($location, $lastModified, $changeFrequency, $priority); 123 | 124 | $this->tags[] = $tag; 125 | 126 | return $tag; 127 | } 128 | 129 | /** 130 | * Add a new expired tag to the sitemap. 131 | * 132 | * @param \Watson\Sitemap\Tags\ExpiredTag|string $location 133 | * @param \DateTimeInterface|string|null $expired 134 | * @return void 135 | */ 136 | public function addExpiredTag($location, $expired = null) 137 | { 138 | $tag = $location instanceof ExpiredTag ? $location : new ExpiredTag($location, $expired); 139 | 140 | $this->tags[] = $tag; 141 | } 142 | 143 | /** 144 | * Retrieve the array of tags. 145 | * 146 | * @return BaseTag[] 147 | */ 148 | public function getTags() 149 | { 150 | return $this->tags; 151 | } 152 | 153 | /** 154 | * Get the formatted sitemap. 155 | * 156 | * @return string 157 | */ 158 | public function xml() 159 | { 160 | return $this->render()->getOriginalContent(); 161 | } 162 | 163 | /** 164 | * Get the formatted sitemap index. 165 | * 166 | * @return string 167 | */ 168 | public function xmlIndex() 169 | { 170 | return $this->index()->getOriginalContent(); 171 | } 172 | 173 | /** 174 | * Render a sitemap. 175 | * 176 | * @return \Illuminate\Http\Response 177 | */ 178 | public function render() 179 | { 180 | if ($cachedView = $this->getCachedView()) { 181 | return response()->make($cachedView, 200, ['Content-type' => 'text/xml']); 182 | } 183 | 184 | $sitemap = response()->view('sitemap::sitemap', [ 185 | '__tags' => $this->getTags(), 186 | '__hasImages' => $this->imagesPresent(), 187 | '__hasVideos' => $this->videosPresent(), 188 | '__isMultilingual' => $this->multilingualTagsPresent() 189 | ], 200, ['Content-type' => 'text/xml']); 190 | 191 | $this->saveCachedView($sitemap); 192 | 193 | return $sitemap; 194 | } 195 | 196 | /** 197 | * Render a sitemap. 198 | * 199 | * @return \Illuminate\Http\Response 200 | */ 201 | public function renderSitemap() 202 | { 203 | return $this->render(); 204 | } 205 | 206 | /** 207 | * Clear all the existing sitemaps and tags. 208 | * 209 | * @return void 210 | */ 211 | public function clear() 212 | { 213 | $this->sitemaps = $this->tags = []; 214 | } 215 | 216 | /** 217 | * Remove all the existing sitemaps. 218 | * 219 | * @return void 220 | */ 221 | public function clearSitemaps() 222 | { 223 | $this->sitemaps = []; 224 | } 225 | 226 | /** 227 | * Remove all the existing tags. 228 | * 229 | * @return void 230 | */ 231 | public function clearTags() 232 | { 233 | $this->tags = []; 234 | } 235 | 236 | /** 237 | * Check whether the sitemap has a cached view or not. 238 | * 239 | * @return bool 240 | */ 241 | public function hasCachedView() 242 | { 243 | if (config('sitemap.cache_enabled')) { 244 | $key = $this->getCacheKey(); 245 | 246 | return $this->cache->has($key); 247 | } 248 | 249 | return false; 250 | } 251 | 252 | /** 253 | * Return whether there are any images present in the sitemap. 254 | * 255 | * @return bool 256 | */ 257 | protected function imagesPresent() 258 | { 259 | foreach ($this->tags as $tag) { 260 | if ($tag->hasImages()) { 261 | return true; 262 | } 263 | } 264 | 265 | return false; 266 | } 267 | 268 | /** 269 | * Return whether there are any videos present in the sitemap. 270 | * 271 | * @return bool 272 | */ 273 | protected function videosPresent() 274 | { 275 | foreach ($this->tags as $tag) { 276 | if ($tag->hasVideos()) { 277 | return true; 278 | } 279 | } 280 | 281 | return false; 282 | } 283 | 284 | /** 285 | * Return whether there are any multilingual tags present in the sitemap. 286 | * 287 | * @return bool 288 | */ 289 | protected function multilingualTagsPresent() 290 | { 291 | foreach ($this->tags as $tag) { 292 | if ($tag instanceof MultilingualTag) { 293 | return true; 294 | } 295 | } 296 | 297 | return false; 298 | } 299 | 300 | /** 301 | * Check to see whether a view has already been cached for the current 302 | * route and if so, return it. 303 | * 304 | * @return mixed 305 | */ 306 | protected function getCachedView() 307 | { 308 | if ($this->hasCachedView()) { 309 | $key = $this->getCacheKey(); 310 | 311 | return $this->cache->get($key); 312 | } 313 | 314 | return false; 315 | } 316 | 317 | /** 318 | * Save a cached view if caching is enabled. 319 | * 320 | * @param \Illuminate\Http\Response $response 321 | * @return void 322 | */ 323 | protected function saveCachedView(Response $response) 324 | { 325 | if (config('sitemap.cache_enabled')) { 326 | $key = $this->getCacheKey(); 327 | 328 | $content = $response->getOriginalContent()->render(); 329 | 330 | if (!$this->cache->get($key)) { 331 | $this->cache->put($key, $content, config('sitemap.cache_length')); 332 | } 333 | } 334 | } 335 | 336 | /** 337 | * Get the cache key that will be used for saving cached sitemaps 338 | * to storage. 339 | * 340 | * @return string 341 | */ 342 | protected function getCacheKey() 343 | { 344 | return 'sitemap_' . Str::slug($this->request->url()); 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/SitemapServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->bind('sitemap', 'Watson\Sitemap\Sitemap'); 24 | 25 | $this->mergeConfigFrom( 26 | __DIR__.'/../../config/config.php', 'sitemap' 27 | ); 28 | } 29 | 30 | /** 31 | * Bootstrap the application events. 32 | * 33 | * @return void 34 | */ 35 | public function boot() 36 | { 37 | $this->loadViewsFrom(__DIR__.'/../../views', 'sitemap'); 38 | 39 | $this->publishes([ 40 | __DIR__.'/../../config/config.php' => config_path('sitemap.php'), 41 | ], 'config'); 42 | 43 | $this->publishes([ 44 | __DIR__.'/../../views' => base_path('resources/views/vendor/sitemap'), 45 | ], 'views'); 46 | } 47 | 48 | /** 49 | * Get the services provided by the provider. 50 | * 51 | * @return array 52 | */ 53 | public function provides() 54 | { 55 | return ['sitemap']; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/BaseTag.php: -------------------------------------------------------------------------------- 1 | 'location', 48 | 'lastmod' => 'lastModified' 49 | ]; 50 | 51 | /** 52 | * Construct the tag. 53 | * 54 | * @param string $location 55 | * @param \DateTimeInterface|string|null $lastModified 56 | * @return void 57 | */ 58 | public function __construct($location, $lastModified = null) 59 | { 60 | $this->location = $location; 61 | 62 | if ($lastModified) { 63 | $this->setLastModified($lastModified); 64 | } 65 | } 66 | 67 | /** 68 | * Get the sitemap location. 69 | * 70 | * @return string 71 | */ 72 | public function getLocation() 73 | { 74 | return $this->location; 75 | } 76 | 77 | /** 78 | * Set the sitemap location. 79 | * 80 | * @param string $location 81 | * @return void 82 | */ 83 | public function setLocation($location) 84 | { 85 | $this->location = $location; 86 | } 87 | 88 | /** 89 | * Get the last modified timestamp. 90 | * 91 | * @return \DateTimeInterface|null 92 | */ 93 | public function getLastModified() 94 | { 95 | return $this->lastModified; 96 | } 97 | 98 | /** 99 | * Set the last modified timestamp. 100 | * 101 | * @param \DateTimeInterface|\Illuminate\Database\Eloquent\Model|string $lastModified 102 | * @return void 103 | */ 104 | public function setLastModified($lastModified) 105 | { 106 | if ($lastModified instanceof DateTimeInterface) { 107 | $this->lastModified = $lastModified; 108 | return; 109 | } elseif ($lastModified instanceof Model) { 110 | $this->lastModified = $lastModified->updated_at; 111 | return; 112 | } 113 | 114 | $this->lastModified = new DateTime($lastModified); 115 | } 116 | 117 | /** 118 | * Add an image tag to the tag. 119 | * 120 | * @param string|ImageTag $location 121 | * @param string|null $caption 122 | * @param string|null $geoLocation 123 | * @param string|null $title 124 | * @param string|null $license 125 | * @return void 126 | */ 127 | public function addImage($location, $caption = null, $geoLocation = null, $title = null, $license = null) 128 | { 129 | $image = $location instanceof ImageTag ? $location : new ImageTag($location, $caption, $geoLocation, $title, $license); 130 | 131 | $this->images[] = $image; 132 | } 133 | 134 | /** 135 | * Add a video tag to the tag. 136 | * 137 | * @param string|VideoTag $location 138 | * @param string|null $title 139 | * @param string|null $description 140 | * @param string|null $thumbnailLocation 141 | * @return void 142 | */ 143 | public function addVideo($location, $title = null, $description = null, $thumbnailLocation = null) 144 | { 145 | $video = $location instanceof VideoTag ? $location : new VideoTag($location, $title, $description, $thumbnailLocation); 146 | 147 | $this->videos[] = $video; 148 | } 149 | 150 | /** 151 | * Get associated image tags. Google image sitemaps only allow up to 152 | * 1,000 images per page. 153 | * 154 | * @return ImageTag[] 155 | */ 156 | public function getImages() 157 | { 158 | return array_slice($this->images, 0, 1000); 159 | } 160 | 161 | /** 162 | * Get associated video tags 163 | * 164 | * @return VideoTag[] 165 | */ 166 | public function getVideos() 167 | { 168 | return $this->videos; 169 | } 170 | 171 | /** 172 | * Tell if the tag has associate image tags 173 | * 174 | * @return boolean 175 | */ 176 | public function hasImages() 177 | { 178 | return count($this->images) > 0; 179 | } 180 | 181 | /** 182 | * Tell if the tag has associate image tags 183 | * 184 | * @return boolean 185 | */ 186 | public function hasVideos() 187 | { 188 | return count($this->videos) > 0; 189 | } 190 | 191 | public function offsetExists($offset) 192 | { 193 | if (array_key_exists($offset, $this->xmlTags)) { 194 | $attribute = $this->xmlTags[$offset]; 195 | 196 | return isset($this->{$attribute}); 197 | } 198 | 199 | return null; 200 | } 201 | 202 | public function offsetGet($offset) 203 | { 204 | if ($this->offsetExists($offset)) { 205 | $attribute = $this->xmlTags[$offset]; 206 | 207 | return $this->{$attribute}; 208 | } 209 | 210 | return null; 211 | } 212 | 213 | public function offsetSet($offset, $value) 214 | { 215 | if (array_key_exists($offset, $this->xmlTags)) { 216 | $attribute = $this->xmlTags[$offset]; 217 | 218 | $this->{$attribute} = $value; 219 | } 220 | } 221 | 222 | public function offsetUnset($offset) 223 | { 224 | if ($attribute = $this->getXmlTagAttribute($offset)) { 225 | unset($this->{$attribute}); 226 | } 227 | 228 | return null; 229 | } 230 | 231 | protected function getXmlTagAttribute($offset) 232 | { 233 | if (array_key_exists($offset, $this->xmlTags)) { 234 | return $this->xmlTags[$offset]; 235 | } 236 | 237 | return null; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/ChangeFrequency.php: -------------------------------------------------------------------------------- 1 | 'location', 25 | 'expired' => 'expired', 26 | ]; 27 | 28 | /** 29 | * Construct the tag. 30 | * 31 | * @param string $location 32 | * @param \DateTimeInterface|string|null $expired 33 | * @return void 34 | */ 35 | public function __construct($location, $expired = null) 36 | { 37 | parent::__construct($location); 38 | 39 | $this->setExpired($expired); 40 | } 41 | 42 | /** 43 | * Get the expired timestamp. 44 | * 45 | * @return \DateTimeInterface 46 | */ 47 | public function getExpired() 48 | { 49 | return $this->expired; 50 | } 51 | 52 | /** 53 | * Set the expiration date 54 | * 55 | * @param \DateTimeInterface|\Illuminate\Database\Eloquent\Model|string $expired 56 | * @return void 57 | */ 58 | public function setExpired($expired) 59 | { 60 | if ($expired instanceof DateTimeInterface) { 61 | $this->expired = $expired; 62 | return; 63 | } elseif ($expired instanceof Model) { 64 | $this->expired = $expired->deleted_at ?: $expired->updated_at; 65 | return; 66 | } 67 | 68 | $this->expired = new DateTime($expired); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/ImageTag.php: -------------------------------------------------------------------------------- 1 | 'location', 42 | 'caption' => 'caption', 43 | 'geo_location' => 'geoLocation', 44 | 'title' => 'title', 45 | 'license' => 'license', 46 | ]; 47 | 48 | /** 49 | * Construct the tag. 50 | * 51 | * @param string $location 52 | * @param string|null $caption 53 | * @param string|null $geoLocation 54 | * @param string|null $title 55 | * @param string|null $license 56 | * @return void 57 | */ 58 | public function __construct($location, $caption = null, $geoLocation = null, $title = null, $license = null) 59 | { 60 | parent::__construct($location); 61 | 62 | $this->caption = $caption; 63 | $this->geoLocation = $geoLocation; 64 | $this->title = $title; 65 | $this->license = $license; 66 | } 67 | 68 | /** 69 | * Get the caption. 70 | * 71 | * @return string|null 72 | */ 73 | public function getCaption() 74 | { 75 | return $this->caption; 76 | } 77 | 78 | /** 79 | * Set the caption. 80 | * 81 | * @param string $caption 82 | * @return void 83 | */ 84 | public function setCaption($caption) 85 | { 86 | $this->caption = $caption; 87 | } 88 | 89 | /** 90 | * Get the geoLocation. 91 | * 92 | * @return string|null 93 | */ 94 | public function getGeoLocation() 95 | { 96 | return $this->geoLocation; 97 | } 98 | 99 | /** 100 | * Set the priority. 101 | * 102 | * @param string $geoLocation 103 | * @return void 104 | */ 105 | public function setGeoLocation($geoLocation) 106 | { 107 | $this->geoLocation = $geoLocation; 108 | } 109 | 110 | /** 111 | * Get the title. 112 | * 113 | * @return string|null 114 | */ 115 | public function getTitle() 116 | { 117 | return $this->title; 118 | } 119 | 120 | /** 121 | * Set the title. 122 | * 123 | * @param string $title 124 | * @return void 125 | */ 126 | public function setTitle($title) 127 | { 128 | $this->title = $title; 129 | } 130 | 131 | /** 132 | * Get the license. 133 | * 134 | * @return string|null 135 | */ 136 | public function getLicense() 137 | { 138 | return $this->license; 139 | } 140 | 141 | /** 142 | * Set the license. 143 | * 144 | * @param string $license 145 | * @return void 146 | */ 147 | public function setLicense($license) 148 | { 149 | $this->license = $license; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/MultilingualTag.php: -------------------------------------------------------------------------------- 1 | 'location', 21 | 'lastmod' => 'lastModified', 22 | 'changefreq' => 'changeFrequency', 23 | 'priority' => 'priority', 24 | 'xhtml:link' => 'multilingual', 25 | ]; 26 | 27 | /** 28 | * Construct the tag. 29 | * 30 | * @param string $location 31 | * @param string|null $lastModified 32 | * @param string|null $changeFrequency 33 | * @param string|null $priority 34 | * @param array $multilingual 35 | * @return void 36 | */ 37 | public function __construct($location, $lastModified = null, $changeFrequency = null, $priority = null, array $multilingual = []) 38 | { 39 | parent::__construct($location, $lastModified, $changeFrequency, $priority); 40 | 41 | $this->multilingual = $multilingual; 42 | } 43 | 44 | /** 45 | * Get the multilingual options. 46 | * 47 | * @return array 48 | */ 49 | public function getMultilingual() 50 | { 51 | return $this->multilingual; 52 | } 53 | 54 | /** 55 | * Set the multilingual options. 56 | * 57 | * @param array $multilingual 58 | * @return void 59 | */ 60 | public function setMultilingual(array $multilingual) 61 | { 62 | $this->multilingual = $multilingual; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/Sitemap.php: -------------------------------------------------------------------------------- 1 | 'location', 28 | 'lastmod' => 'lastModified', 29 | 'changefreq' => 'changeFrequency', 30 | 'priority' => 'priority' 31 | ]; 32 | 33 | /** 34 | * Construct the tag. 35 | * 36 | * @param string $location 37 | * @param \DateTimeInterface|string|null $lastModified 38 | * @param string|null $changeFrequency 39 | * @param string|null $priority 40 | * @return void 41 | */ 42 | public function __construct($location, $lastModified = null, $changeFrequency = null, $priority = null) 43 | { 44 | parent::__construct($location, $lastModified); 45 | 46 | $this->changeFrequency = $changeFrequency; 47 | $this->priority = $priority; 48 | } 49 | 50 | /** 51 | * Get the change frequency. 52 | * 53 | * @return string|null 54 | */ 55 | public function getChangeFrequency() 56 | { 57 | return $this->changeFrequency; 58 | } 59 | 60 | /** 61 | * Set the change frequency. 62 | * 63 | * @param \Watson\Sitemap\Tags\ChangeFrequency|string $changeFrequency 64 | * @return void 65 | */ 66 | public function setChangeFrequency($changeFrequency) 67 | { 68 | $this->changeFrequency = $changeFrequency; 69 | } 70 | 71 | /** 72 | * Get the priority. 73 | * 74 | * @return string|null 75 | */ 76 | public function getPriority() 77 | { 78 | return $this->priority; 79 | } 80 | 81 | /** 82 | * Set the priority. 83 | * 84 | * @param string $priority 85 | * @return void 86 | */ 87 | public function setPriority($priority) 88 | { 89 | $this->priority = $priority; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/Video/VideoPlatformTag.php: -------------------------------------------------------------------------------- 1 | platforms = array_intersect($platforms, $this::$allowedPlatforms); 45 | 46 | if (in_array($relationship, $this::$allowedRelationships)) { 47 | $this->relationship = $relationship; 48 | } 49 | } 50 | 51 | /** 52 | * Get the tag platforms. 53 | * 54 | * @return string 55 | */ 56 | public function getPlatforms() 57 | { 58 | return implode(' ', $this->platforms); 59 | } 60 | 61 | /** 62 | * Get the tag relationship. 63 | * 64 | * @return string 65 | */ 66 | public function getRelationship() 67 | { 68 | return $this->relationship; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/Video/VideoPriceTag.php: -------------------------------------------------------------------------------- 1 | price = $price; 45 | $this->currency = $currency; 46 | } 47 | 48 | /** 49 | * Get the tag type. 50 | * 51 | * @return string 52 | */ 53 | public function getType() 54 | { 55 | return $this->type; 56 | } 57 | 58 | /** 59 | * Set the tag type. 60 | * 61 | * @param string $type 62 | * @return void 63 | */ 64 | public function setType($type) 65 | { 66 | $this->type = $type; 67 | } 68 | 69 | /** 70 | * Get the tag resolution. 71 | * 72 | * @return string 73 | */ 74 | public function getResolution() 75 | { 76 | return $this->resolution; 77 | } 78 | 79 | /** 80 | * Set the tag resolution. 81 | * 82 | * @param string $resolution 83 | * @return void 84 | */ 85 | public function setResolution($resolution) 86 | { 87 | $this->resolution = $resolution; 88 | } 89 | 90 | /** 91 | * Get the tag price. 92 | * 93 | * @return float 94 | */ 95 | public function getPrice() 96 | { 97 | return $this->price; 98 | } 99 | 100 | /** 101 | * Set the tag price. 102 | * 103 | * @param float $price 104 | * @return void 105 | */ 106 | public function setPrice($price) 107 | { 108 | $this->price = $price; 109 | } 110 | 111 | /** 112 | * Get the tag currency. 113 | * 114 | * @return string 115 | */ 116 | public function getCurrency() 117 | { 118 | return $this->currency; 119 | } 120 | 121 | /** 122 | * Set the tag currency. 123 | * 124 | * @param string $currency 125 | * @return void 126 | */ 127 | public function setCurrency($currency) 128 | { 129 | $this->currency = $currency; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/Video/VideoRestrictionTag.php: -------------------------------------------------------------------------------- 1 | countries = $countries; 38 | 39 | if (in_array($relationship, self::$allowedRelationships)) { 40 | $this->relationship = $relationship; 41 | } 42 | } 43 | 44 | /** 45 | * Get the tag countries. 46 | * 47 | * @return string 48 | */ 49 | public function getCountries() 50 | { 51 | return implode(' ', $this->countries); 52 | } 53 | 54 | /** 55 | * Get the tag relationship. 56 | * 57 | * @return string 58 | */ 59 | public function getRelationship() 60 | { 61 | return $this->relationship; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Watson/Sitemap/Tags/Video/VideoTag.php: -------------------------------------------------------------------------------- 1 | title = $title; 164 | $this->description = $description; 165 | $this->thumbnailLocation = $thumbnailLocation; 166 | } 167 | 168 | /** 169 | * Get the tag title. 170 | * 171 | * @return string 172 | */ 173 | public function getTitle() 174 | { 175 | return $this->title; 176 | } 177 | 178 | /** 179 | * Get the tag description. 180 | * 181 | * @return string 182 | */ 183 | public function getDescription() 184 | { 185 | return $this->description; 186 | } 187 | 188 | /** 189 | * Get the thumbnail location. 190 | * 191 | * @return string 192 | */ 193 | public function getThumbnailLocation() 194 | { 195 | return $this->thumbnailLocation; 196 | } 197 | 198 | /** 199 | * Get the content location. 200 | * 201 | * @return string 202 | */ 203 | public function getContentLocation() 204 | { 205 | return $this->contentLocation; 206 | } 207 | 208 | /** 209 | * Set the content location. 210 | * 211 | * @param string $contentLocation 212 | * @return void 213 | */ 214 | public function setContentLocation($contentLocation) 215 | { 216 | $this->contentLocation = $contentLocation; 217 | } 218 | 219 | /** 220 | * Get the player location. 221 | * 222 | * @return string 223 | */ 224 | public function getPlayerLocation() 225 | { 226 | return $this->playerLocation; 227 | } 228 | 229 | /** 230 | * Set the player location. 231 | * 232 | * @param string $playerLocation 233 | * @return void 234 | */ 235 | public function setPlayerLocation($playerLocation) 236 | { 237 | $this->playerLocation = $playerLocation; 238 | } 239 | 240 | /** 241 | * Get the video duration. 242 | * 243 | * @return int 244 | */ 245 | public function getDuration() 246 | { 247 | return $this->duration; 248 | } 249 | 250 | /** 251 | * Set the video duration. 252 | * 253 | * @param int $duration 254 | * @return void 255 | */ 256 | public function setDuration($duration) 257 | { 258 | $this->duration = $duration; 259 | } 260 | 261 | /** 262 | * Get the expiration date. 263 | * 264 | * @return \DateTimeInterface 265 | */ 266 | public function getExpirationDate() 267 | { 268 | return $this->expirationDate; 269 | } 270 | 271 | /** 272 | * Set the expiration date. 273 | * 274 | * @param \DateTimeInterface $expirationDate 275 | * @return void 276 | */ 277 | public function setExpirationDate(DateTimeInterface $expirationDate) 278 | { 279 | $this->expirationDate = $expirationDate; 280 | } 281 | 282 | /** 283 | * Get the video rating. 284 | * 285 | * @return float 286 | */ 287 | public function getRating() 288 | { 289 | return $this->rating; 290 | } 291 | 292 | /** 293 | * Set the video rating. 294 | * 295 | * @param float $rating 296 | * @return void 297 | */ 298 | public function setRating($rating) 299 | { 300 | $this->rating = $rating; 301 | } 302 | 303 | /** 304 | * Get the view count. 305 | * 306 | * @return int 307 | */ 308 | public function getViewCount() 309 | { 310 | return $this->viewCount; 311 | } 312 | 313 | /** 314 | * Set the view count. 315 | * 316 | * @param int $viewCount 317 | * @return void 318 | */ 319 | public function setViewCount($viewCount) 320 | { 321 | $this->viewCount = $viewCount; 322 | } 323 | 324 | /** 325 | * Get the publication date. 326 | * 327 | * @return \DateTimeInterface 328 | */ 329 | public function getPublicationDate() 330 | { 331 | return $this->publicationDate; 332 | } 333 | 334 | /** 335 | * Set the publication date. 336 | * 337 | * @param \DateTimeInterface $publicationDate 338 | * @return void 339 | */ 340 | public function setPublicationDate(DateTimeInterface $publicationDate) 341 | { 342 | $this->publicationDate = $publicationDate; 343 | } 344 | 345 | /** 346 | * Get the family friendly status. 347 | * 348 | * @return bool 349 | */ 350 | public function getFamilyFriendly() 351 | { 352 | return $this->familyFriendly; 353 | } 354 | 355 | /** 356 | * Set the family friendly status. 357 | * 358 | * @param bool $familyFriendly 359 | */ 360 | public function setFamilyFriendly(bool $familyFriendly) 361 | { 362 | $this->familyFriendly = $familyFriendly; 363 | } 364 | 365 | /** 366 | * Get the tags. 367 | * 368 | * @return array 369 | */ 370 | public function getTags() 371 | { 372 | return $this->tags; 373 | } 374 | 375 | /** 376 | * Set the tags. 377 | * 378 | * @param array $tags 379 | * @return void 380 | */ 381 | public function setTags(array $tags) 382 | { 383 | $this->tags = $tags; 384 | } 385 | 386 | /** 387 | * Get the category. 388 | * 389 | * @return string 390 | */ 391 | public function getCategory() 392 | { 393 | return $this->category; 394 | } 395 | 396 | /** 397 | * Set the category. 398 | * 399 | * @param string $category 400 | * @return void 401 | */ 402 | public function setCategory($category) 403 | { 404 | $this->category = $category; 405 | } 406 | 407 | /** 408 | * Get the tag restriction. 409 | * 410 | * @return VideoRestrictionTag 411 | */ 412 | public function getRestriction() 413 | { 414 | return $this->restriction; 415 | } 416 | 417 | /** 418 | * Set the tag restriction. 419 | * 420 | * @param VideoRestrictionTag $restriction 421 | * @return void 422 | */ 423 | public function setRestriction(VideoRestrictionTag $restriction) 424 | { 425 | $this->restriction = $restriction; 426 | } 427 | 428 | /** 429 | * Get the gallery location. 430 | * 431 | * @return string 432 | */ 433 | public function getGalleryLocation() 434 | { 435 | return $this->galleryLocation; 436 | } 437 | 438 | /** 439 | * Set the gallery location. 440 | * 441 | * @param string $galleryLocation 442 | * @return string 443 | */ 444 | public function setGalleryLocation($galleryLocation) 445 | { 446 | $this->galleryLocation = $galleryLocation; 447 | } 448 | 449 | /** 450 | * Get the tag prices. 451 | * 452 | * @return VideoPriceTag[] 453 | */ 454 | public function getPrices() 455 | { 456 | return $this->prices; 457 | } 458 | 459 | /** 460 | * Set the tag prices. 461 | * 462 | * @param VideoPriceTag[] $prices 463 | * @return void 464 | */ 465 | public function setPrices($prices) 466 | { 467 | $this->prices = $prices; 468 | } 469 | 470 | /** 471 | * Get whether a subscription is required. 472 | * 473 | * @return bool 474 | */ 475 | public function getRequiresSubscription() 476 | { 477 | return $this->requiresSubscription; 478 | } 479 | 480 | /** 481 | * Set whether a subscription is required. 482 | * 483 | * @param bool $requiresSubscription 484 | * @return void 485 | */ 486 | public function setRequiresSubscription(bool $requiresSubscription) 487 | { 488 | $this->requiresSubscription = $requiresSubscription; 489 | } 490 | 491 | /** 492 | * Get the uploader. 493 | * 494 | * @return string 495 | */ 496 | public function getUploader() 497 | { 498 | return $this->uploader; 499 | } 500 | 501 | /** 502 | * Set the uploader. 503 | * 504 | * @param string $uploader 505 | * @return void 506 | */ 507 | public function setUploader($uploader) 508 | { 509 | $this->uploader = $uploader; 510 | } 511 | 512 | /** 513 | * Get the platform. 514 | * 515 | * @return VideoPlatformTag 516 | */ 517 | public function getPlatform() 518 | { 519 | return $this->platform; 520 | } 521 | 522 | /** 523 | * Set the platform. 524 | * 525 | * @param VideoPlatformTag $platform 526 | * @return void 527 | */ 528 | public function setPlatform(VideoPlatformTag $platform) 529 | { 530 | $this->platform = $platform; 531 | } 532 | 533 | /** 534 | * Get the live status. 535 | * 536 | * @return bool 537 | */ 538 | public function getLive() 539 | { 540 | return $this->live; 541 | } 542 | 543 | /** 544 | * Set the live status. 545 | * 546 | * @param bool $live 547 | * @return void 548 | */ 549 | public function setLive(bool $live) 550 | { 551 | $this->live = $live; 552 | } 553 | } 554 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | false, 17 | 18 | 'cache_length' => 1440 19 | ]; 20 | -------------------------------------------------------------------------------- /src/views/sitemap.php: -------------------------------------------------------------------------------- 1 | ' ?> 2 | xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" 4 | xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" 5 | xmlns:xhtml="http://www.w3.org/1999/xhtml"> 6 | 7 | 8 | getLocation(), ENT_XML1) ?> 9 | getLastModified()): ?> 10 | getLastModified()->format('Y-m-d\TH:i:sP') ?> 11 | 12 | 13 | getChangeFrequency()): ?> 14 | getChangeFrequency() ?> 15 | 16 | getPriority()): ?> 17 | getPriority() ?> 18 | 19 | 20 | 21 | getMultilingual() as $lang => $href): ?> 22 | 23 | 24 | 25 | 26 | getExpired()->format('Y-m-d\TH:i:sP') ?> 27 | 28 | getImages() as $__image): ?> 29 | 30 | getLocation() ?> 31 | getCaption()): ?> 32 | getCaption()) ?> 33 | 34 | getGeoLocation()): ?> 35 | getGeoLocation()) ?> 36 | 37 | getTitle()): ?> 38 | getTitle()) ?> 39 | 40 | getLicense()): ?> 41 | getLicense()) ?> 42 | 43 | 44 | 45 | getVideos() as $__video): ?> 46 | 47 | getThumbnailLocation()): ?> 48 | getThumbnailLocation()) ?> 49 | 50 | getTitle()): ?> 51 | getTitle()) ?> 52 | 53 | getDescription()): ?> 54 | getDescription()) ?> 55 | 56 | getContentLocation() && !$__video->getPlayerLocation()): ?> 57 | getContentLocation()) ?> 58 | 59 | getPlayerLocation() && !$__video->getContentLocation()): ?> 60 | getPlayerLocation()) ?> 61 | 62 | getDuration()): ?> 63 | getDuration() ?> 64 | 65 | getExpirationDate()): ?> 66 | getExpirationDate()->format('Y-m-d\TH:i:sP') ?> 67 | 68 | getRating()): ?> 69 | getRating() ?> 70 | 71 | getViewCount()): ?> 72 | getViewCount() ?> 73 | 74 | getPublicationDate()): ?> 75 | getPublicationDate()->format('Y-m-d\TH:i:sP') ?> 76 | 77 | getFamilyFriendly() ? 'yes' : 'no' ?> 78 | getRestriction()): ?> 79 | getRestriction()->getCountries() ?> 80 | 81 | getGalleryLocation()): ?> 82 | getGalleryLocation()) ?> 83 | 84 | getPrices() as $__price): ?> 85 | getResolution()): ?> resolution="getResolution() ?>" 88 | getType()): ?> type="getType() ?>" >getPrice() ?> 89 | 90 | getRequiresSubscription() ? 'yes' : 'no' ?> 91 | getUploader()): ?> 92 | getUploader()) ?> 93 | 94 | getLive() ? 'yes' : 'no' ?> 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/views/sitemaps.php: -------------------------------------------------------------------------------- 1 | ' ?> 2 | 3 | 4 | 5 | getLocation(), ENT_XML1) ?> 6 | getLastModified()): ?> 7 | getLastModified()->format('Y-m-d\TH:i:sP') ?> 8 | 9 | 10 | 11 | 12 | --------------------------------------------------------------------------------