better_seo 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +476 -11
- data/lib/better_seo/version.rb +1 -1
- data/lib/better_seo.rb +3 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96812d57f991f56ae85d042ed90d67cd804da41be917f557c9035b7103704fa0
|
|
4
|
+
data.tar.gz: ba04b33847262251dbce411840acee273e7f36c3f25e3b02a6fd2aaacf88bbe9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 587ba80330156dc5a305ea2d92831939fa9f80b6341bdb1052d639d371b8892d9827ddd0ce24b4b07c0c67714aec87151dcc31bc515031aee055a10703d3bf0f
|
|
7
|
+
data.tar.gz: 8dfe3c3526d621ee904535484e70529c68550d2388f289408a40f044651f154f6cb424f8715967d3d9dcaf8aa652f48bdb0ddda1e505c882c37f8fe01c9a1dbc
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2025-01-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Sitemap generation system with comprehensive XML sitemap support
|
|
14
|
+
- `Sitemap::UrlEntry` - Individual URL entry with full sitemap.org protocol support
|
|
15
|
+
- `Sitemap::Builder` - Fluent API for building sitemaps with method chaining
|
|
16
|
+
- `Sitemap::Generator` - High-level generator with multiple generation strategies
|
|
17
|
+
- Sitemap generation methods
|
|
18
|
+
- `generate` - Generate from block with fluent builder
|
|
19
|
+
- `generate_from` - Generate from array of URLs
|
|
20
|
+
- `generate_from_collection` - Generate from model collections with lambda support
|
|
21
|
+
- `write_to_file` - Write sitemap directly to file with automatic directory creation
|
|
22
|
+
- URL entry features
|
|
23
|
+
- Support for all sitemap attributes: loc, lastmod, changefreq, priority
|
|
24
|
+
- Automatic date formatting (Date, Time, DateTime objects)
|
|
25
|
+
- XML entity escaping for security
|
|
26
|
+
- Validation for URL format, protocol (HTTP/HTTPS), and required fields
|
|
27
|
+
- Dynamic attribute generation
|
|
28
|
+
- Lambda/Proc support for dynamic lastmod, changefreq, and priority
|
|
29
|
+
- Conditional logic based on model attributes
|
|
30
|
+
- Rails integration examples
|
|
31
|
+
- Controller actions for dynamic sitemap serving
|
|
32
|
+
- Rake tasks for sitemap generation
|
|
33
|
+
- Service object patterns for production use
|
|
34
|
+
- Multi-model sitemap examples
|
|
35
|
+
- Comprehensive error handling
|
|
36
|
+
- 28 error class tests added
|
|
37
|
+
- Full coverage of all error types
|
|
38
|
+
|
|
39
|
+
### Test Coverage
|
|
40
|
+
- 384 tests passing (+98 from v0.4.0)
|
|
41
|
+
- 99.71% code coverage (681/683 lines)
|
|
42
|
+
- 69 new tests for sitemap functionality
|
|
43
|
+
|
|
10
44
|
## [0.4.0] - 2025-01-23
|
|
11
45
|
|
|
12
46
|
### Added
|
data/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
A comprehensive SEO gem for Ruby and Rails applications. BetterSeo provides a clean, fluent DSL for managing meta tags, Open Graph, Twitter Cards, structured data, sitemaps, and more.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/yourusername/better_seo)
|
|
6
|
+
[](https://github.com/yourusername/better_seo)
|
|
7
7
|
[](https://www.ruby-lang.org)
|
|
8
8
|
[](https://rubyonrails.org)
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
### ✅ Implemented (v0.
|
|
12
|
+
### ✅ Implemented (v0.5.0)
|
|
13
13
|
|
|
14
14
|
- **Core Configuration System**
|
|
15
15
|
- Singleton configuration with block-style setup
|
|
@@ -38,23 +38,33 @@ A comprehensive SEO gem for Ruby and Rails applications. BetterSeo provides a cl
|
|
|
38
38
|
- Automatic HTML safety with `raw` helper
|
|
39
39
|
- Integration with global configuration defaults
|
|
40
40
|
|
|
41
|
+
- **Sitemap Generation**
|
|
42
|
+
- **XML Sitemap Builder**: Fluent API for building sitemaps
|
|
43
|
+
- **Sitemap Generator**: Generate from blocks, arrays, or model collections
|
|
44
|
+
- **URL Entry**: Full sitemap.org protocol support (loc, lastmod, changefreq, priority)
|
|
45
|
+
- **Dynamic Generation**: Lambda support for dynamic attributes
|
|
46
|
+
- **File Writing**: Write sitemaps directly to files
|
|
47
|
+
- **Rails Integration**: Controller actions and Rake tasks
|
|
48
|
+
- **Validation**: Automatic URL validation (format, protocol)
|
|
49
|
+
- **Method Chaining**: Fluent interface for adding multiple URLs
|
|
50
|
+
|
|
41
51
|
### 🚧 Planned
|
|
42
52
|
|
|
43
|
-
- **Advanced Generators** (v0.
|
|
53
|
+
- **Advanced Generators** (v0.6.0)
|
|
44
54
|
- Schema.org JSON-LD generator
|
|
45
55
|
- Breadcrumbs generator
|
|
46
56
|
- AMP HTML generator
|
|
47
57
|
|
|
48
|
-
- **Advanced Rails Integration** (v0.
|
|
58
|
+
- **Advanced Rails Integration** (v0.6.0)
|
|
49
59
|
- Controller helpers for setting page SEO
|
|
50
60
|
- Railtie for automatic initialization
|
|
51
61
|
- Generator for initializer file
|
|
52
62
|
|
|
53
|
-
- **Sitemap
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
63
|
+
- **Advanced Sitemap Features** (v0.6.0)
|
|
64
|
+
- Multi-language sitemap support (hreflang)
|
|
65
|
+
- Sitemap index for large sites (50,000+ URLs)
|
|
66
|
+
- Image/video sitemap extensions
|
|
67
|
+
- News sitemap support
|
|
58
68
|
|
|
59
69
|
- **Advanced Features** (v0.6.0+)
|
|
60
70
|
- robots.txt generator
|
|
@@ -64,10 +74,12 @@ A comprehensive SEO gem for Ruby and Rails applications. BetterSeo provides a cl
|
|
|
64
74
|
|
|
65
75
|
## Installation
|
|
66
76
|
|
|
77
|
+
### For Production Use (when published to RubyGems)
|
|
78
|
+
|
|
67
79
|
Add this line to your application's Gemfile:
|
|
68
80
|
|
|
69
81
|
```ruby
|
|
70
|
-
gem 'better_seo'
|
|
82
|
+
gem 'better_seo', '~> 0.5.0'
|
|
71
83
|
```
|
|
72
84
|
|
|
73
85
|
And then execute:
|
|
@@ -82,6 +94,23 @@ Or install it yourself as:
|
|
|
82
94
|
gem install better_seo
|
|
83
95
|
```
|
|
84
96
|
|
|
97
|
+
### For Development (from source)
|
|
98
|
+
|
|
99
|
+
Add this line to your application's Gemfile:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
gem 'better_seo', git: 'https://github.com/alessiobussolari/better_seo.git', tag: 'v0.5.0'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or clone and build locally:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
git clone https://github.com/alessiobussolari/better_seo.git
|
|
109
|
+
cd better_seo
|
|
110
|
+
gem build better_seo.gemspec
|
|
111
|
+
gem install better_seo-0.5.0.gem
|
|
112
|
+
```
|
|
113
|
+
|
|
85
114
|
## Quick Start
|
|
86
115
|
|
|
87
116
|
### 1. Configuration
|
|
@@ -555,6 +584,442 @@ Then use it in your views:
|
|
|
555
584
|
og_image: url_for(@article.cover_image) %>
|
|
556
585
|
```
|
|
557
586
|
|
|
587
|
+
### 6. Sitemap Generation
|
|
588
|
+
|
|
589
|
+
BetterSeo provides a comprehensive sitemap generation system with support for XML sitemaps, dynamic content, and model collections.
|
|
590
|
+
|
|
591
|
+
#### Basic Sitemap Generation
|
|
592
|
+
|
|
593
|
+
Generate a simple sitemap using the block syntax:
|
|
594
|
+
|
|
595
|
+
```ruby
|
|
596
|
+
xml = BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
597
|
+
sitemap.add_url("https://example.com")
|
|
598
|
+
sitemap.add_url("https://example.com/about")
|
|
599
|
+
sitemap.add_url("https://example.com/contact")
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
puts xml
|
|
603
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
604
|
+
# <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
605
|
+
# <url>
|
|
606
|
+
# <loc>https://example.com</loc>
|
|
607
|
+
# <changefreq>weekly</changefreq>
|
|
608
|
+
# <priority>0.5</priority>
|
|
609
|
+
# </url>
|
|
610
|
+
# ...
|
|
611
|
+
# </urlset>
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
#### URL Entry with Full Attributes
|
|
615
|
+
|
|
616
|
+
Add URLs with all sitemap attributes (lastmod, changefreq, priority):
|
|
617
|
+
|
|
618
|
+
```ruby
|
|
619
|
+
xml = BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
620
|
+
sitemap.add_url(
|
|
621
|
+
"https://example.com",
|
|
622
|
+
lastmod: Date.today,
|
|
623
|
+
changefreq: "daily",
|
|
624
|
+
priority: 1.0
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
sitemap.add_url(
|
|
628
|
+
"https://example.com/blog",
|
|
629
|
+
lastmod: "2024-01-15",
|
|
630
|
+
changefreq: "weekly",
|
|
631
|
+
priority: 0.8
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
sitemap.add_url(
|
|
635
|
+
"https://example.com/about",
|
|
636
|
+
changefreq: "monthly",
|
|
637
|
+
priority: 0.5
|
|
638
|
+
)
|
|
639
|
+
end
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
**Valid changefreq values**: `always`, `hourly`, `daily`, `weekly`, `monthly`, `yearly`, `never`
|
|
643
|
+
|
|
644
|
+
**Priority range**: 0.0 to 1.0 (default: 0.5)
|
|
645
|
+
|
|
646
|
+
#### Method Chaining
|
|
647
|
+
|
|
648
|
+
The builder supports fluent method chaining:
|
|
649
|
+
|
|
650
|
+
```ruby
|
|
651
|
+
xml = BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
652
|
+
sitemap
|
|
653
|
+
.add_url("https://example.com", priority: 1.0)
|
|
654
|
+
.add_url("https://example.com/about", priority: 0.8)
|
|
655
|
+
.add_url("https://example.com/contact", priority: 0.6)
|
|
656
|
+
end
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
#### Generate from Array
|
|
660
|
+
|
|
661
|
+
Create a sitemap from an array of URLs:
|
|
662
|
+
|
|
663
|
+
```ruby
|
|
664
|
+
urls = [
|
|
665
|
+
"https://example.com",
|
|
666
|
+
"https://example.com/about",
|
|
667
|
+
"https://example.com/contact",
|
|
668
|
+
"https://example.com/blog"
|
|
669
|
+
]
|
|
670
|
+
|
|
671
|
+
xml = BetterSeo::Sitemap::Generator.generate_from(
|
|
672
|
+
urls,
|
|
673
|
+
changefreq: "weekly",
|
|
674
|
+
priority: 0.7
|
|
675
|
+
)
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
#### Generate from Model Collection
|
|
679
|
+
|
|
680
|
+
Generate sitemaps dynamically from your Rails models:
|
|
681
|
+
|
|
682
|
+
```ruby
|
|
683
|
+
# Simple example with Post model
|
|
684
|
+
xml = BetterSeo::Sitemap::Generator.generate_from_collection(
|
|
685
|
+
Post.published,
|
|
686
|
+
url: ->(post) { "https://example.com/posts/#{post.slug}" },
|
|
687
|
+
lastmod: ->(post) { post.updated_at },
|
|
688
|
+
changefreq: "weekly",
|
|
689
|
+
priority: 0.8
|
|
690
|
+
)
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Dynamic attributes with lambdas**:
|
|
694
|
+
|
|
695
|
+
```ruby
|
|
696
|
+
xml = BetterSeo::Sitemap::Generator.generate_from_collection(
|
|
697
|
+
Article.all,
|
|
698
|
+
url: ->(article) { "https://example.com/articles/#{article.slug}" },
|
|
699
|
+
lastmod: ->(article) { article.updated_at },
|
|
700
|
+
changefreq: ->(article) do
|
|
701
|
+
article.featured? ? "daily" : "weekly"
|
|
702
|
+
end,
|
|
703
|
+
priority: ->(article) do
|
|
704
|
+
article.featured? ? 0.9 : 0.6
|
|
705
|
+
end
|
|
706
|
+
)
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
#### Rails Routes Integration
|
|
710
|
+
|
|
711
|
+
Generate sitemap from Rails routes:
|
|
712
|
+
|
|
713
|
+
```ruby
|
|
714
|
+
# config/routes.rb
|
|
715
|
+
Rails.application.routes.draw do
|
|
716
|
+
# Your routes...
|
|
717
|
+
|
|
718
|
+
# Sitemap endpoint
|
|
719
|
+
get '/sitemap.xml', to: 'sitemaps#index', defaults: { format: 'xml' }
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
# app/controllers/sitemaps_controller.rb
|
|
723
|
+
class SitemapsController < ApplicationController
|
|
724
|
+
def index
|
|
725
|
+
@sitemap_xml = generate_sitemap
|
|
726
|
+
render xml: @sitemap_xml
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
private
|
|
730
|
+
|
|
731
|
+
def generate_sitemap
|
|
732
|
+
BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
733
|
+
# Static pages
|
|
734
|
+
sitemap.add_url(root_url, priority: 1.0, changefreq: "daily")
|
|
735
|
+
sitemap.add_url(about_url, priority: 0.8, changefreq: "monthly")
|
|
736
|
+
sitemap.add_url(contact_url, priority: 0.7, changefreq: "monthly")
|
|
737
|
+
|
|
738
|
+
# Dynamic content from models
|
|
739
|
+
Post.published.find_each do |post|
|
|
740
|
+
sitemap.add_url(
|
|
741
|
+
post_url(post),
|
|
742
|
+
lastmod: post.updated_at,
|
|
743
|
+
changefreq: "weekly",
|
|
744
|
+
priority: 0.8
|
|
745
|
+
)
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
Category.all.find_each do |category|
|
|
749
|
+
sitemap.add_url(
|
|
750
|
+
category_url(category),
|
|
751
|
+
lastmod: category.updated_at,
|
|
752
|
+
changefreq: "weekly",
|
|
753
|
+
priority: 0.7
|
|
754
|
+
)
|
|
755
|
+
end
|
|
756
|
+
end
|
|
757
|
+
end
|
|
758
|
+
end
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### Write Sitemap to File
|
|
762
|
+
|
|
763
|
+
Save sitemap directly to a file:
|
|
764
|
+
|
|
765
|
+
```ruby
|
|
766
|
+
# In a Rake task or script
|
|
767
|
+
BetterSeo::Sitemap::Generator.write_to_file('public/sitemap.xml') do |sitemap|
|
|
768
|
+
sitemap.add_url("https://example.com", priority: 1.0)
|
|
769
|
+
|
|
770
|
+
Post.published.find_each do |post|
|
|
771
|
+
sitemap.add_url(
|
|
772
|
+
"https://example.com/posts/#{post.slug}",
|
|
773
|
+
lastmod: post.updated_at,
|
|
774
|
+
changefreq: "weekly",
|
|
775
|
+
priority: 0.8
|
|
776
|
+
)
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
# Returns the file path: "public/sitemap.xml"
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
#### Rake Task for Sitemap Generation
|
|
784
|
+
|
|
785
|
+
Create a Rake task to regenerate your sitemap:
|
|
786
|
+
|
|
787
|
+
```ruby
|
|
788
|
+
# lib/tasks/sitemap.rake
|
|
789
|
+
namespace :sitemap do
|
|
790
|
+
desc "Generate sitemap.xml"
|
|
791
|
+
task generate: :environment do
|
|
792
|
+
file_path = BetterSeo::Sitemap::Generator.write_to_file('public/sitemap.xml') do |sitemap|
|
|
793
|
+
# Add static pages
|
|
794
|
+
sitemap.add_url("#{ENV['SITE_URL']}", priority: 1.0, changefreq: "daily")
|
|
795
|
+
sitemap.add_url("#{ENV['SITE_URL']}/about", priority: 0.8)
|
|
796
|
+
sitemap.add_url("#{ENV['SITE_URL']}/contact", priority: 0.7)
|
|
797
|
+
|
|
798
|
+
# Add dynamic content
|
|
799
|
+
Post.published.find_each do |post|
|
|
800
|
+
sitemap.add_url(
|
|
801
|
+
"#{ENV['SITE_URL']}/posts/#{post.slug}",
|
|
802
|
+
lastmod: post.updated_at,
|
|
803
|
+
changefreq: "weekly",
|
|
804
|
+
priority: 0.8
|
|
805
|
+
)
|
|
806
|
+
end
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
puts "Sitemap generated at #{file_path}"
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
# Run with: rake sitemap:generate
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
#### Using the Builder Directly
|
|
817
|
+
|
|
818
|
+
For more control, use the Builder class directly:
|
|
819
|
+
|
|
820
|
+
```ruby
|
|
821
|
+
builder = BetterSeo::Sitemap::Builder.new
|
|
822
|
+
|
|
823
|
+
# Add URLs
|
|
824
|
+
builder.add_url("https://example.com", priority: 1.0)
|
|
825
|
+
builder.add_url("https://example.com/about", priority: 0.8)
|
|
826
|
+
|
|
827
|
+
# Add multiple URLs at once
|
|
828
|
+
builder.add_urls(
|
|
829
|
+
["https://example.com/blog", "https://example.com/contact"],
|
|
830
|
+
changefreq: "weekly",
|
|
831
|
+
priority: 0.7
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
# Remove a URL
|
|
835
|
+
builder.remove_url("https://example.com/contact")
|
|
836
|
+
|
|
837
|
+
# Check size
|
|
838
|
+
puts builder.size # => 3
|
|
839
|
+
|
|
840
|
+
# Iterate over URLs
|
|
841
|
+
builder.each do |url|
|
|
842
|
+
puts "#{url.loc} - Priority: #{url.priority}"
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Generate XML
|
|
846
|
+
xml = builder.to_xml
|
|
847
|
+
|
|
848
|
+
# Validate all URLs
|
|
849
|
+
builder.validate! # Raises ValidationError if any URL is invalid
|
|
850
|
+
|
|
851
|
+
# Clear all URLs
|
|
852
|
+
builder.clear
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
#### URL Entry Details
|
|
856
|
+
|
|
857
|
+
Work with individual URL entries:
|
|
858
|
+
|
|
859
|
+
```ruby
|
|
860
|
+
entry = BetterSeo::Sitemap::UrlEntry.new(
|
|
861
|
+
"https://example.com/page",
|
|
862
|
+
lastmod: Date.today,
|
|
863
|
+
changefreq: "daily",
|
|
864
|
+
priority: 0.8
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
# Access attributes
|
|
868
|
+
entry.loc # => "https://example.com/page"
|
|
869
|
+
entry.lastmod # => "2024-01-15"
|
|
870
|
+
entry.changefreq # => "daily"
|
|
871
|
+
entry.priority # => 0.8
|
|
872
|
+
|
|
873
|
+
# Update attributes
|
|
874
|
+
entry.lastmod = Date.new(2024, 1, 20)
|
|
875
|
+
entry.changefreq = "weekly"
|
|
876
|
+
entry.priority = 0.9
|
|
877
|
+
|
|
878
|
+
# Generate XML for single entry
|
|
879
|
+
entry.to_xml
|
|
880
|
+
# <url>
|
|
881
|
+
# <loc>https://example.com/page</loc>
|
|
882
|
+
# <lastmod>2024-01-20</lastmod>
|
|
883
|
+
# <changefreq>weekly</changefreq>
|
|
884
|
+
# <priority>0.9</priority>
|
|
885
|
+
# </url>
|
|
886
|
+
|
|
887
|
+
# Convert to hash
|
|
888
|
+
entry.to_h
|
|
889
|
+
# {
|
|
890
|
+
# loc: "https://example.com/page",
|
|
891
|
+
# lastmod: "2024-01-20",
|
|
892
|
+
# changefreq: "weekly",
|
|
893
|
+
# priority: 0.9
|
|
894
|
+
# }
|
|
895
|
+
|
|
896
|
+
# Validate
|
|
897
|
+
entry.validate! # Raises ValidationError if invalid
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### Advanced: Multi-Model Sitemap
|
|
901
|
+
|
|
902
|
+
Combine multiple models in a single sitemap:
|
|
903
|
+
|
|
904
|
+
```ruby
|
|
905
|
+
xml = BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
906
|
+
# Homepage
|
|
907
|
+
sitemap.add_url("https://example.com", priority: 1.0, changefreq: "daily")
|
|
908
|
+
|
|
909
|
+
# Blog posts
|
|
910
|
+
Post.published.find_each do |post|
|
|
911
|
+
sitemap.add_url(
|
|
912
|
+
"https://example.com/posts/#{post.slug}",
|
|
913
|
+
lastmod: post.updated_at,
|
|
914
|
+
changefreq: post.featured? ? "daily" : "weekly",
|
|
915
|
+
priority: post.featured? ? 0.9 : 0.7
|
|
916
|
+
)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
# Categories
|
|
920
|
+
Category.all.find_each do |category|
|
|
921
|
+
sitemap.add_url(
|
|
922
|
+
"https://example.com/categories/#{category.slug}",
|
|
923
|
+
lastmod: category.updated_at,
|
|
924
|
+
changefreq: "weekly",
|
|
925
|
+
priority: 0.6
|
|
926
|
+
)
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
# Static pages
|
|
930
|
+
%w[about contact privacy terms].each do |page|
|
|
931
|
+
sitemap.add_url(
|
|
932
|
+
"https://example.com/#{page}",
|
|
933
|
+
changefreq: "monthly",
|
|
934
|
+
priority: 0.5
|
|
935
|
+
)
|
|
936
|
+
end
|
|
937
|
+
end
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
#### Validation
|
|
941
|
+
|
|
942
|
+
All URLs are automatically validated when generating:
|
|
943
|
+
|
|
944
|
+
```ruby
|
|
945
|
+
# This will raise BetterSeo::ValidationError
|
|
946
|
+
xml = BetterSeo::Sitemap::Generator.generate do |sitemap|
|
|
947
|
+
sitemap.add_url("") # Error: Location is required
|
|
948
|
+
sitemap.add_url("not-a-valid-url") # Error: Invalid URL format
|
|
949
|
+
sitemap.add_url("ftp://example.com") # Error: Must be HTTP/HTTPS
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
# Validate manually
|
|
953
|
+
builder = BetterSeo::Sitemap::Builder.new
|
|
954
|
+
builder.add_url("https://example.com")
|
|
955
|
+
builder.validate! # Returns true if all URLs valid
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
#### Complete Example: Production Sitemap
|
|
959
|
+
|
|
960
|
+
```ruby
|
|
961
|
+
# app/services/sitemap_generator_service.rb
|
|
962
|
+
class SitemapGeneratorService
|
|
963
|
+
def self.generate
|
|
964
|
+
BetterSeo::Sitemap::Generator.write_to_file(Rails.root.join('public', 'sitemap.xml')) do |sitemap|
|
|
965
|
+
add_static_pages(sitemap)
|
|
966
|
+
add_blog_posts(sitemap)
|
|
967
|
+
add_categories(sitemap)
|
|
968
|
+
add_products(sitemap) if defined?(Product)
|
|
969
|
+
end
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
private_class_method def self.add_static_pages(sitemap)
|
|
973
|
+
sitemap.add_url(Rails.application.routes.url_helpers.root_url, priority: 1.0, changefreq: "daily")
|
|
974
|
+
sitemap.add_url(Rails.application.routes.url_helpers.about_url, priority: 0.8, changefreq: "monthly")
|
|
975
|
+
sitemap.add_url(Rails.application.routes.url_helpers.contact_url, priority: 0.7, changefreq: "monthly")
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
private_class_method def self.add_blog_posts(sitemap)
|
|
979
|
+
Post.published.find_each do |post|
|
|
980
|
+
sitemap.add_url(
|
|
981
|
+
Rails.application.routes.url_helpers.post_url(post),
|
|
982
|
+
lastmod: post.updated_at,
|
|
983
|
+
changefreq: post.frequently_updated? ? "daily" : "weekly",
|
|
984
|
+
priority: calculate_post_priority(post)
|
|
985
|
+
)
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
private_class_method def self.add_categories(sitemap)
|
|
990
|
+
Category.all.find_each do |category|
|
|
991
|
+
sitemap.add_url(
|
|
992
|
+
Rails.application.routes.url_helpers.category_url(category),
|
|
993
|
+
lastmod: category.posts.maximum(:updated_at),
|
|
994
|
+
changefreq: "weekly",
|
|
995
|
+
priority: 0.6
|
|
996
|
+
)
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
private_class_method def self.add_products(sitemap)
|
|
1001
|
+
Product.available.find_each do |product|
|
|
1002
|
+
sitemap.add_url(
|
|
1003
|
+
Rails.application.routes.url_helpers.product_url(product),
|
|
1004
|
+
lastmod: product.updated_at,
|
|
1005
|
+
changefreq: "daily",
|
|
1006
|
+
priority: product.featured? ? 0.95 : 0.75
|
|
1007
|
+
)
|
|
1008
|
+
end
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
private_class_method def self.calculate_post_priority(post)
|
|
1012
|
+
base_priority = 0.7
|
|
1013
|
+
base_priority += 0.2 if post.featured?
|
|
1014
|
+
base_priority += 0.1 if post.comments_count > 10
|
|
1015
|
+
[base_priority, 1.0].min
|
|
1016
|
+
end
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
# Call from rake task or controller:
|
|
1020
|
+
# SitemapGeneratorService.generate
|
|
1021
|
+
```
|
|
1022
|
+
|
|
558
1023
|
## Configuration Reference
|
|
559
1024
|
|
|
560
1025
|
### Global Configuration
|
data/lib/better_seo/version.rb
CHANGED
data/lib/better_seo.rb
CHANGED
|
@@ -14,6 +14,9 @@ require_relative "better_seo/generators/meta_tags_generator"
|
|
|
14
14
|
require_relative "better_seo/generators/open_graph_generator"
|
|
15
15
|
require_relative "better_seo/generators/twitter_cards_generator"
|
|
16
16
|
require_relative "better_seo/rails/helpers/seo_helper"
|
|
17
|
+
require_relative "better_seo/sitemap/url_entry"
|
|
18
|
+
require_relative "better_seo/sitemap/builder"
|
|
19
|
+
require_relative "better_seo/sitemap/generator"
|
|
17
20
|
|
|
18
21
|
module BetterSeo
|
|
19
22
|
class << self
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: better_seo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- alessiobussolari
|
|
@@ -53,8 +53,8 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0.22'
|
|
55
55
|
description: BetterSeo provides a clean, fluent DSL for managing meta tags, Open Graph,
|
|
56
|
-
Twitter Cards, and more. Features include automatic HTML generation,
|
|
57
|
-
|
|
56
|
+
Twitter Cards, XML sitemaps, and more. Features include automatic HTML generation,
|
|
57
|
+
dynamic sitemap generation, validation, Rails integration, and 99.7% test coverage.
|
|
58
58
|
email:
|
|
59
59
|
- alessio@cosmic.tech
|
|
60
60
|
executables: []
|