<h1>Check list SEO <img alt="Build" src="https://travis-ci.org/itarverne/checklist-seo.svg?branch=master"></h1>
<p><img alt="" src="./static/images/seo_logo.png"></p>
<p><a href="https://codeclimate.com/github/itarverne/checklist-seo/maintainability" rel="nofollow"><img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/1ea9094958cb77a0c1a9/maintainability"></a>
<a href="https://codeclimate.com/github/itarverne/checklist-seo/test_coverage" rel="nofollow"><img alt="Test Coverage" src="https://api.codeclimate.com/v1/badges/1ea9094958cb77a0c1a9/test_coverage"></a></p>
<h1>Features</h1>
<ul>
<li>Keyword repartition</li>
<li>Length content</li>
<li>Check title article length</li>
<li>Url is optimized</li>
<li>Number internal Links</li>
</ul>
<h1>Installation</h1>
<h2>Pypi</h2>
<p><a href="https://pypi.org/project/checklist-seo/" rel="nofollow"><img alt="PyPI version" src="https://img.shields.io/pypi/v/checklist-seo"></a></p>
<p><code>pip install checklist-seo</code></p>
<h2>Installing the application in Django</h2>
<p>To use this application, you need first to add it to your config file.</p>
<p>In your config file (ex: settings.py):</p>
<pre><code># Application definition
INSTALLED_APPS = [
...
'seo'
...
]
</code></pre>
<h2>SEO Pannel</h2>
<p>To setup the keyword for SEO, you need to add a special SEO Pannel that will appear in your page creation in wagtail admin.</p>
<p>The module contains a model in models/SeoPage, the model need to be used as a base for your page models.</p>
<p>Example of your model:</p>
<pre><span class="k">class</span> <span class="nc">HomePage</span><span class="p">(</span><span class="n">SeoPage</span><span class="p">):</span>
<span class="n">date</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">(</span><span class="s2">"Post date"</span><span class="p">)</span>
<span class="n">intro</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">250</span><span class="p">)</span>
<span class="n">delay</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">validators</span><span class="o">=</span><span class="p">[</span><span class="n">MaxValueValidator</span><span class="p">(</span><span class="mi">99</span><span class="p">),</span> <span class="n">MinValueValidator</span><span class="p">(</span><span class="mi">0</span><span class="p">)])</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">StreamField</span><span class="p">([</span>
<span class="p">(</span><span class="s1">'text'</span><span class="p">,</span> <span class="n">RichTextBlock</span><span class="p">(</span><span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">features</span><span class="o">=</span><span class="p">[</span><span class="s1">'h2'</span><span class="p">,</span> <span class="s1">'h3'</span><span class="p">,</span> <span class="s1">'h4'</span><span class="p">,</span> <span class="s1">'bold'</span><span class="p">,</span> <span class="s1">'italic'</span><span class="p">,</span> <span class="s1">'link'</span><span class="p">,</span>
<span class="s1">'code'</span><span class="p">,</span> <span class="s1">'ol'</span><span class="p">,</span> <span class="s1">'ul'</span><span class="p">,</span> <span class="s1">'hr'</span><span class="p">,</span> <span class="s1">'document-link'</span><span class="p">,</span> <span class="s1">'image'</span><span class="p">,</span> <span class="s1">'embed'</span><span class="p">,</span> <span class="s1">'superscript'</span><span class="p">,</span> <span class="s1">'subscript'</span><span class="p">,</span> <span class="s1">'strikethrough'</span><span class="p">,</span> <span class="s1">'blockquote'</span><span class="p">])),</span>
<span class="p">(</span><span class="s1">'rawHtml'</span><span class="p">,</span> <span class="n">RawHTMLBlock</span><span class="p">(</span><span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)),</span>
<span class="p">],</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">images_keyword</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">250</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">selected_image</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
<span class="s1">'wagtailimages.Image'</span><span class="p">,</span>
<span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">SET_NULL</span><span class="p">,</span>
<span class="n">related_name</span><span class="o">=</span><span class="s1">'+'</span>
<span class="p">)</span>
<span class="n">keep_slug</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="p">(</span><span class="s1">'Keep current slug'</span><span class="p">),</span>
<span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">help_text</span><span class="o">=</span><span class="p">(</span><span class="s2">"Keep current slug or save to generate a new slug."</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">_get_autogenerated_slug</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">base_slug</span><span class="p">):</span>
<span class="sd">"""Redefinition of wagtail's _get_autogenerated_slug so you can use your own slug generator."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">slug</span>
<span class="n">search_fields</span> <span class="o">=</span> <span class="n">Page</span><span class="o">.</span><span class="n">search_fields</span> <span class="o">+</span> <span class="p">[</span>
<span class="n">index</span><span class="o">.</span><span class="n">SearchField</span><span class="p">(</span><span class="s1">'intro'</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">content_panels</span> <span class="o">=</span> <span class="n">Page</span><span class="o">.</span><span class="n">content_panels</span> <span class="o">+</span> <span class="p">[</span>
<span class="n">MultiFieldPanel</span><span class="p">([</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'date'</span><span class="p">),</span>
<span class="n">FieldRowPanel</span><span class="p">([</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'delay'</span><span class="p">),</span>
<span class="p">]),</span>
<span class="p">],</span> <span class="n">heading</span><span class="o">=</span><span class="s2">"Blog information"</span><span class="p">),</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'intro'</span><span class="p">),</span>
<span class="n">StreamFieldPanel</span><span class="p">(</span><span class="s1">'body'</span><span class="p">),</span>
<span class="n">FieldRowPanel</span><span class="p">([</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'images_keyword'</span><span class="p">),</span>
<span class="p">],</span> <span class="n">heading</span><span class="o">=</span><span class="s2">"Images"</span><span class="p">),</span>
<span class="n">ImageChooserPanel</span><span class="p">(</span><span class="n">field_name</span><span class="o">=</span><span class="s2">"selected_image"</span><span class="p">,</span> <span class="n">heading</span><span class="o">=</span><span class="s2">"Image sélectionnée"</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">promote_panels</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">MultiFieldPanel</span><span class="p">([</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'slug'</span><span class="p">),</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'keep_slug'</span><span class="p">),</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'seo_title'</span><span class="p">),</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'show_in_menus'</span><span class="p">),</span>
<span class="n">FieldPanel</span><span class="p">(</span><span class="s1">'search_description'</span><span class="p">),</span>
<span class="p">],</span> <span class="n">heading</span><span class="o">=</span><span class="s2">"Common Page Configuration"</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">edit_handler</span> <span class="o">=</span> <span class="n">TabbedInterface</span><span class="p">([</span>
<span class="n">ObjectList</span><span class="p">(</span><span class="n">content_panels</span><span class="p">,</span> <span class="n">heading</span><span class="o">=</span><span class="s1">'Content'</span><span class="p">),</span>
<span class="n">ObjectList</span><span class="p">(</span><span class="n">promote_panels</span><span class="p">,</span> <span class="n">heading</span><span class="o">=</span><span class="s2">"Promote"</span><span class="p">),</span>
<span class="n">SeoPage</span><span class="o">.</span><span class="n">seo_object_list</span><span class="p">,</span>
<span class="n">ObjectList</span><span class="p">(</span><span class="n">Page</span><span class="o">.</span><span class="n">settings_panels</span><span class="p">,</span> <span class="n">heading</span><span class="o">=</span><span class="s1">'Settings'</span><span class="p">)</span>
<span class="p">])</span>
</pre>
<h2>Routing</h2>
<p>In your routing projet file <code>urls.py</code></p>
<pre><span class="kn">from</span> <span class="nn">django.conf.urls</span> <span class="kn">import</span> <span class="n">url</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">include</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="o">...</span>
<span class="n">url</span><span class="p">(</span><span class="sa">r</span><span class="s1">'^seo/'</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s1">'seo.urls'</span><span class="p">),</span> <span class="n">name</span><span class="o">=</span><span class="s1">'seo'</span><span class="p">),</span>
<span class="p">]</span>
</pre>
<h2>Static</h2>
<p>To get the CSS / JS / Image file from this app to your projet
<code>python manage.py collectstatic</code></p>
<h2>DB Migration</h2>
<p>Now you can detect the change
<code>python manage.py makemigrations</code></p>
<p>And apply it on DB
<code>python manage.py migration</code></p>
<h2>Test</h2>
<p><code>pytest</code></p>