Back-End

29 out, 2015

Como criar um CMS simples em PHP com links amigáveis para SEO

Publicidade

Atualmente, os motores de busca como o Google dão valor cada vez mais à experiência do usuário fornecida pelos sites para classificá-los. Então, SEO muitas vezes significa fazer os sites mais amigáveis aos usuários.

Um aspecto que contribui para o bom posicionamento em buscas dos sites é a URL amigável, que permite ao usuário saber sobre o que é determinada página apenas pela URL.

Neste artigo, veremos como criar um sistema de gerenciamento de conteúdo (CMS) simples que usa URLs amigáveis ​​para as páginas de conteúdo, para que você possa implementar em seus próprios projetos sem ter que usar outros CMS grandes.

Introdução

Search Engine Optimization (SEO) é muito importante para qualquer site hoje. Se você não otimizar seu site, ninguém vai encontrá-lo nos motores de busca. E não há nenhum uso para um site se ninguém pode encontrá-lo.

Este artigo explica apenas um aspecto de SEO, que é ter páginas com URLs amigáveis. Muitos anos atrás, estávamos todos loucos com phpNuke ou Joomla, mas eles tiveram um problema desagradável, os links de páginas eram muito feios: “index.php?id=653&page_type=blog&lang=en”. Eles eram muito difíceis de escrever e todos pareciam iguais. Os motores de busca também não gostam desses tipos de URLs.

Em seguida, uma nova geração de CMS saiu, alguns usando, por exemplo, o framework CodeIgniter, outros usando Moodle ou Drupal. Mas eles também tinham seus próprios problemas de SEO. Você ainda pode encontrá-los atualmente, mas um novo herói surgiu muito rápido depois, que foi o WordPress.

Uma armadilha que todos os CMSs têm é que eles são feitos para sites de propósitos gerais. Por exemplo, o WordPress começou como um sistema de blogs, agora oferece plug-ins para fazer qualquer tipo de sites. Mas, para um sistema como esse, você precisa de classes enormes, muito código, plug-ins demais e muita manutenção.

Outra coisa é que você não pode vender código na licença GPL para clientes sem abrir o código-fonte. Eles irão, eventualmente, ouvir em algum lugar que você os fez pagar por um software de fonte aberta, e eles podem não gostar disso.

Perante isso, provavelmente, a melhor solução é fazer o seu próprio CMS, leve. Você pode licenciá-lo como quiser, você sabe muito bem como você o escreveu e é bom ter uma solução personalizada com uma estrutura de banco de dados personalizado.

O problema que terá de enfrentar é que vamos voltar para a questão do “index.php?id=653&page_type=blog&lang=en”. Então, vamos ver como fazer um simples CMS com SEO URLs amigáveis.

Explicando os conceitos

Links amigáveis para SEO devem conter o título da página, precisam ser legíveis e devem se livrar do index.php. Por exemplo, “como-tornar-seo-amigável-para-links” ou “fazendo-uma-classe-para-site-php-classes”, como você pode ver, não têm index.php, não há qualquer nome de extensão de arquivo, de modo que é muito legível e você pode obter o título pelo link. Um ponto importante é que esses links devem ser gerados dinamicamente, pois essa é a ideia de ter um CMS.

Então, voltamos ao “index.php?id=653&page_type=blog&lang=en”; ao resolver isso, teremos “index.php”, é o arquivo PHP principal para processar todas as requisições no CMS.

Nós temos a ID do artigo ou página, temos um tipo de página, nesse caso, “blog”, mas pode ser qualquer coisa, produto, artigo ou blog. Finalmente temos um idioma, nesse caso, é para sites com mais de uma linguagem – neste artigo, vou pular o idioma. Precisamos imitar a mesma funcionalidade no nosso link “como-tornar-seo-amigável-para-links”, mas não temos qualquer elemento desses acima, então fazemos assim:

  1. Redirecionar todas as requisições de URL para um lugar para processamento.
  2. Conferir a tabela de links e pegar os dados que precisamos, ID e tipo.
  3. Dependendo do tipo de elemento, chamaremos um plug-in adequado para processar e mostrar os dados.

Tratando todas as requisições com um só script

Se queremos que todas as URLs sejam tratadas por um script, digamos index.php, precisamos então configurar o arquivo .htaccess. Precisamos ter um Apache ou algum outro servidor Web que forneça controle equivalente da configuração por meio de um arquivo .htaccess. O arquivo .htaccess deve habilitar o módulo de regravação da URL usando a diretiva RewriteEngine. Em seguida, basta adicionar uma regra para todo o tráfego ir para index.php.

RewriteEngine on
RewriteRule !((.php)|(.html)|(.htm)|images\/(.*)|css\/(.*)|js\/(.*))$ index.php [NC]

É importante definir essas diretivas com muita atenção. No exemplo acima, estou redirecionando todo o tráfego para index.php, a não ser que alguém acesse um arquivo PHP ou HTML diretamente, ou se o caminho pedido estiver em pastas de imagens, CSS ou JS. É aí que minhas imagens, arquivos CSS e JavaScript geralmente estão.

O uso da marcação [NC] faz com que o RewriteRule seja compensado de forma case-sensitive. Ou seja, ele não se importa se as letras aparecem como maiúsculas ou minúsculas na URI correspondida.

Bem-vindo ao index.php

Agora que temos todo o tráfego sendo manipulado no index.php, precisamos fazer uma verificação geral: quem esteve aqui e do que ele precisa. index.php será como um gerente de tráfego. Precisamos pegar o link de entrada e consultar uma tabela especial em um banco de dados MySQL com todos os nossos links gerados anteriormente, pegamos a ID e o tipo de página associada à URL. Vamos ver a estrutura da tabela em primeiro lugar.

CREATE TABLE urls (
 id int(9) NOT NULL AUTO_INCREMENT,
 url varchar(255) NOT NULL,
 urltype varchar(255) NOT NULL,
 element int(9) NOT NULL,
 PRIMARY KEY (id),
 KEY url (url),
 KEY urltype (urltype)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Nesse caso, element irá refletir a ID e urltype como o seu tipo. Agora, vamos ver o código PHP:

<?php
 $link = str_replace( "/", "", urldecode( $_SERVER[ "REQUEST_URI" ] ));
 $db_connection = new mysqli( "localhost", "dbuser", "pasword123", "cms");
 $db_connection->query( "SET NAMES 'UTF8'" );
 $statement = $db_connection->prepare( "SELECT type, element FROM urls WHERE url = ?" );
 $statement->bind_param( "s", $link);
 $statement->execute();
 $statement->bind_result($type,$id);
 $statement->fetch();
 $statement->close();
 if($id == 0){
  header('Location: /page-not-found');
 }
 $db_connection->close();
?>

Como você pode ver, em primeiro lugar temos a URL solicitada, vamos fazer o “urlencoded” e remover o caractere “/”. Então, consultaremos o banco de dados com uma declaração preparada para obter o tipo e a identificação do nosso elemento. Se o elemento não existir, nós redirecionamos o código para uma “página não encontrada”.

Obtendo os detalhes da URL

Depois de obter o tipo e a ID do nosso elemento, é fácil fazer o resto. Precisamos fazer outra consulta para obter os detalhes do elemento, dependendo do tipo da URL.

Vamos supor que temos dois tipos de elementos em nosso CMS: produtos e blogs. Se é um blog, consultamos a tabela de blogs e fazemos a requisição do arquivo blog.php para processar a página. Se é um produto, consultamos a tabela de produtos e obtemos os detalhes, então nós chamamos products.php para mostrar esse template. Essas são as tabelas de produtos e blogs:

CREATE TABLE blogs (
 id int(9) NOT NULL AUTO_INCREMENT,
 title varchar(255) NOT NULL,
 blog varchar(255) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE products (
 id int(9) NOT NULL AUTO_INCREMENT,
 product varchar(255) NOT NULL,
 details varchar(255) NOT NULL,
 price float(5,2) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

E agora o código PHP, onde vamos usar um switch case statement para determinar o que fazer, dependendo do tipo de página.

Se o tipo de elemento é “produto”, executamos uma consulta à tabela de produtos e obtemos os detalhes do produto; em seguida, chamamos o arquivo product_show.php para mostrar o template de visualização de produto.

Se o tipo de elemento é “blog”, fazemos a mesma coisa, mas na tabela blogs, e em seguida chamamos blog_view.php onde você vai fazer o seu template de blog.

<?php
 switch($type){
  case "product":
   $db_connection = new mysqli("localhost", "dbuser", "pasword123", "cms");
   $db_connection->query( "SET NAMES 'UTF8'" );
   $statement = $db_connection->prepare( "SELECT id, product, details, price FROM products WHERE id = ?" );
   $statement->bind_param( "i", $id );
   $statement->execute();
   $statement->bind_result( $productid, $product, $details, $price);
   $statement->fetch();
   $statement->close();
   $db_connection->close();
   require_once "product_view.php";
    break;
  case "blog":
   $db_connection = new mysqli( "localhost", "dbuser", "pasword123", "cms");
   $db_connection->query( "SET NAMES 'UTF8'" );
   $statement = $db_connection->prepare( "SELECT id, title, blog FROM blogs WHERE id = ?");
   $statement->bind_param( "i", $id);
   $statement->execute();
   $statement->bind_result( $blogid, $title, $blog);
   $statement->fetch();
   $statement->close();
   $db_connection->close();
   require_once "blog_view.php";
    break;
 }
?>

Criando os links na interface de administração

Vimos como redirecionar solicitações de URL para index.php e mostramos o produto solicitado ou blog dependendo da URL. Mas agora nós precisamos ver como criamos esses links na administração e como enchê-los na tabela “urls”.

Ao adicionar um blog, todos os dados serão inseridos na tabela “blogs”, por isso é preciso obter o insert blog post ID. Vamos usar essa ID na nossa tabela “urls”. Precisamos também do título para criar o link para ele. É aí que nós vamos usar a função create_link ().

<?php
 function insert_blog(){
  $db_connection = new mysqli("localhost", "dbuser", "pasword123", "cms");
  $db_connection->query("SET NAMES 'UTF8'");
  $statement = $db_connection->prepare( "INSERT INTO blogs( title, blog) VALUES ( ?, ? )");
  $statement->bind_param("ss", $_POST[ 'title' ], $_POST[ 'blog' ]);
  $statement->execute();
  $statement->close();
  $inserted_id = $statement->insert_id;
  
  // Here we generate an URL from the title
  $url = create_link( $_POST['title'] );
  
  // Here we add a link to our urls table
  $statement = $db_connection->prepare( "INSERT INTO urls( url, urltype, element) VALUES (?, 'blog', ?)");
  $statement->bind_param("si", $url, $inserted_id);
  $statement->execute();
  $statement->close();
  $db_connection->close();
 }
?>

Como você pode ver, nós sempre inserimos o blog em primeiro lugar, em seguida, o insert ID, e então obtemos o título. Em seguida, criamos uma nova URL a partir do título usando a função create_link para que possamos inserir uma nova linha na tabela de urls. Como definimos urltype para ‘blog’ para distinguir entre blogs e produtos na tabela de urls, vamos fazer o mesmo para produtos:

<?php
 function insert_product(){
  $db_connection = new mysqli( "localhost", "dbuser", "pasword123", "cms");
  $db_connection->query("SET NAMES 'UTF8'");
  $statement = $db_connection->prepare( "INSERT INTO products( product, details, price) VALUES (?, ?, ?)");
  $statement->bind_param("ssd", $_POST[ 'title' ], $_POST[ 'details' ], $_POST[ 'price' ]);
  $statement->execute();
  $statement->close();
  $inserted_id = $statement->insert_id;
  
  // Now we generate an URL from the title
  $url = create_link( $_POST[ 'title' ]);
  
  // Now we add a link to our urls table
  $statement = $db_connection->prepare( "INSERT INTO urls( url, urltype, element) VALUES (?, 'product', ?)");
  $statement->bind_param("si", $url, $inserted_id);
  $statement->execute();
  $statement->close();
  $db_connection->close();
 }
?>

E agora vamos ver como a função “create_link” se parece:

<?php
 function create_link($title) {
  $title = strtolower($title);
  $title = str_replace('&','and', $title);
  $title = str_replace(';', '-', $title);
  $title = str_replace(':', '-', $title);
  $title = str_replace(',', '-', $title);
  $title = str_replace('–', '-', $title);
  $title = str_replace('/', '-', $title);
  $title = str_replace(' - ', '-', $title);
  $title = str_replace('"', '-', $title);
  $title = str_replace(' ', '-', $title);
  
  $db_connection = new mysqli( "localhost", "dbuser", "pasword123", "cms";
  $db_connection->query("SET NAMES 'UTF8'");
  $statement = $db_connection->prepare( "SELECT id FROM urls WHERE url = ? limit 1");
  $statement->bind_param("s", $title);
  $statement->execute();
  $statement->bind_result($id);
  $statement->fetch();
  $statement->close();
  $db_connection->close();
  
  if($id == 0) {
   return $title;
  } else {
    create_link( $title. "-". strtolower( generateRandomString(7) ));
  }
 }
 
 function generateRandomString( $length = 10) {
  $characters = '0123456789'. 'abcdefghijkl'. 'mnopqrstuvwxyz'. 'ABCDEFGHIJKL'. 'MNOPQRSTUVWXYZ';
  $randomString = '';
  for ($i = 0; $i < $length; $i++) {
   $randomString .= $characters[ rand(0, strlen( $characters ) - 1)];
  }
  return $randomString;
 }
?>

A função “create_link” pega o título do blog ou do produto e faz com que ele seja uma string de letras minúsculas. Em seguida, ele remove todos os caracteres especiais usando str_replace e substitui quaisquer espaços em branco com o caractere “-“.

O resultado é uma URL amigável para SEO, que vamos precisar verificar se já está em uso na tabela de URLs. Nós não queremos nenhuma duplicata, todas as URLs precisam ser exclusivas na tabela. Se a URL for encontrada, retornarmos o resultado a ser inserido.

No caso de já termos essa URL, usamos a função generateRandomString, que gera uma sequência aleatória, e adicionamos isso ao final da URL gerada. Em seguida, chamamos o “create_link” de forma recursiva até chegarmos a uma URL única para a inserção.

O código é escrito de uma forma simples para que você possa entender o conceito. Ele não é para ser tomado como algo bem testado em um verdadeiro CMS.

Conclusão

Criar URLs amigáveis para usuários e SEO não é difícil. Muitos CMSs existentes podem cuidar disso para você. Mas se por algum motivo você precisa implementar sua própria solução e quer um CMS completo, este artigo apresenta as etapas básicas que você pode seguir para resolver esse assunto sem depender de outros softwares.

Se você gostou deste artigo, ou você tem alguma dúvida, basta deixar um comentário.

***

Ashraf Gheith faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://www.phpclasses.org/blog/post/303-How-to-create-a-simple-PHP-CMS-with-SEO-friendly-links.html