Etapa 1 : Criar o template do seu formulário
No subdiretório formulaires/ da sua pasta «squelettes», crie o arquivo contact.html que vai conter o código HTML do seu formulário de contato. Por exemplo:
<form action='#ENV{action}' method='post'>
	#ACTION_FORMULAIRE{#ENV{action}}
	<label>Seu e-mail</label>
	<input type='text' name='email' value='#ENV{email}' />
	<br />
	<label>Sua mensagem</label>
	<textarea name='message'>#ENV{message}</textarea>
	<input type='submit' name='ok' value='ok' />
</form>
Como você pode constatar, este formulário contem algumas particularidades:
-  o atributo action da tag 
<form>contém#ENV{action}que é o URL para o qual o formulário será enviado; -  
#ACTION_FORMULAIRE{#ENV{action}}indica ao SPIP que deve transmitir às funções «charger, verifier, traiter» os dados informados e aqueles eventualmente contidos no URL (após o SPIP 2.1 o argumento#ENV{action}é, na realidade, inútil, sendo atualmente o valor padrão); -  cada input, textarea ou select contém o valor 
#ENV{xxx}onde xxx corresponde ao atributo name correspondente. 
A esta altura, você já pode exibir este formulário em um template, com a tag #FORMULAIRE_CONTACT ou diretamente no texto de uma matéria, com o código <formulaire|contact>. Você vai apreciar poder testar e refinar a aparência e o conteúdo do seu formulário sem escrever uma única linha de PHP.
No entanto, se você preencher os campos e clicar no botão OK, o seu formulário não fará nada, e você não encontrará os dados que informou.
Etapa 2: a função charger
Vamos então indicar ao SPIP quais são os campos que o visitate pode preencher.
Para isso, crie um ficheiro contact.php no seu subdiretório formulaires/ (ao lado do seu template contact.html), e insira o código a seguir:
<?php
function formulaires_contact_charger_dist(){
	$valeurs = array('email'=>'','message'=>'');
	
	return $valeurs;
}
?>
O que este código faz?
Ele declara a função charger do formulário contact do diretorio formulaires consecutivametne nomeado formulaires_contact_charger.
O sufixo _dist assinala que se trata da função charger padrão deste formulário, mas que ela é eventualmente personalizável (ver, a propósito de surcharges http://programmer.spip.org/Surcharg...).
Esta função lista, na variável $valeurs, os campos de entrada de dados do seu formulário e, para cada campo, o valor inicial padrão
A função formulaires_contact_charger_dist envia esta lista de campos.
Teste novamente o seu formulário: se você preencher os campos e validar com o botão )K, você verá que, desta vez, o formulário não perdeu os valores que você informou (mesmo que ainda não faça mais nada).
Neste exemplo, todos os campos estão vazios por padrão. Podemos melhorar a nossa função, preenchendo automaticamente o e-mail, caso o visitante esteja identificado.
Isto nos dará o código a seguir para a função charger:
function formulaires_contact_charger_dist(){
	$valeurs = array('email'=>'','message'=>'');
	if (isset($GLOBALS['visiteur_session']['email']))
		$valeurs['email'] = $GLOBALS['visiteur_session']['email'];
	return $valeurs;
}
Se você testar agora o seu formulário, estando identificado, você constatará:
- que o campo email já está previamente preenchido com o e-mail da sua conta SPIP
 - que os valores informados ou alterados são conservados tal com após da validação.
 
Etapa 3: Verificar que os dados são válidos
Antes de considerar os valores informados pelo visitante, devemos evidentemente verificar se os dados informados são válidos.
Vamos, por exemplo, definir as restrições a seguir:
- os campos emal e mensagem são obrigatórios
 - o e-mail deve ser válido
 
Para verificar a entrada de dados, vamos criar a função formulaires_contact_verifier_dist (no mesmo modelo da função charger) sempre no mesmo ficheiro contact.php :
function formulaires_contact_verifier_dist(){
	$erreurs = array();
	// verificar se os campos obrigatórios foram preenchidos:
	foreach(array('email','message') as $obligatoire)
		if (!_request($obligatoire)) $erreurs[$obligatoire] = 'Este campo é obrigatório';
	
	// verificar se um e-mail foi informado e se é válido:
	include_spip('inc/filtres');
	if (_request('email') AND !email_valide(_request('email')))
		$erreurs['email'] = 'Este e-mail não é válido';
	if (count($erreurs))
		$erreurs['message_erreur'] = 'Os dados que você informou contêm erros!';
	return $erreurs;
}
Nota: o uso de _request() é explicado no site no site programmer.spip.org
A função verificar envia uma lista de campos em erro, com a mensagem de erro correspondente a cada campo.
A esta altura, você não verá nada de diferente, se você testar o formulário: com efeito, o seu formulário contact.html não exibe erros. Você irá completá-lo como abaixo:
[<p class='formulaire_erreur'>(#ENV*{message_erreur})</p>]
<form action='#ENV{action}' method='post'>
	#ACTION_FORMULAIRE{#ENV{action}}
	<label>Seu e-mail</label>
	[<span class='erreur'>(#ENV**{erreurs}|table_valeur{email})</span>]
	<input type='text' name='email' value='#ENV{email}' />
	<br />
	<label>Sua mensagem</label>
	[<span class='erreur'>(#ENV**{erreurs}|table_valeur{message})</span>]
	<textarea name='message'>#ENV{message}</textarea>
	<input type='submit' name='ok' value='ok' />
</form>
Note bem:
-  a exibição de uma mensagem de erro genérica enviada pela função verifier 
[<p class='reponse_formulaire reponse_formulaire_erreur'>(#ENV*{message_erreur})</p>] -  as mensagens de erro à frente de cada campo:
[<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email})</span>] 
Você pode agora testar o seu formulário, informando um e-mail erróneo ou deixando um campo vazio: o seu formulário já começa a interagir com o visitante!!
Etapa 4 : tratar!
Assim que a função verifier não envie nenhum erro, o SPIP chama automaticamente a função de tratamento correspondente. Vamos declarar esta função formulaires_contact_traiter_dist (sempre no ficheiro contact.php) e vamos enviar um e-mail ao webmaster:
function formulaires_contact_traiter_dist(){
	$envoyer_mail = charger_fonction('envoyer_mail','inc');
	$email_to = $GLOBALS['meta']['email_webmaster'];
	$email_from = _request('email');
	$sujet = 'Formulário de contato';
	$message = _request('message');	
	$envoyer_mail($email_to,$sujet,$message,$email_from);
	return array('message_ok'=>'A sua mensagem foi recebida corretamente. Você receberá uma resposta em breve!');
}
Você notará que a função traiter não faz nenhuma verificação: elas foram todas feitas previamente (pela função verifier). Se a função traiter for chamada, é porque não há nenhum erro.
A função traiter envia uma mensagem de sucesso, « message_ok », contida numa tabela. Como para as mensagens de erro, falta completar o nosso formulário para que ele exiba a mensagem. Como abaixo:
[<p class='formulaire_ok'>(#ENV*{message_ok})</p>]
[<p class='formulaire_erreur'>(#ENV*{message_erreur})</p>]
[(#EDITABLE|oui)
	<form action='#ENV{action}' method='post'>
		#ACTION_FORMULAIRE{#ENV{action}}
		<label>Seu e-mail</label>
		[<span class='erreur'>(#ENV**{erreurs}|table_valeur{email})</span>]
		<input type='text' name='email' value='#ENV{email}' />
		<br />
		<label>Sua mensagem</label>
		[<span class='erreur'>(#ENV**{erreurs}|table_valeur{message})</span>]
		<textarea name='message'>#ENV{message}</textarea>
		<input type='submit' name='ok' value='ok' />
	</form>
]
Note bem:
-  a exibição de uma mensagem de sucesso no início
[<p class="formulaire_message">(#ENV*{message_ok})</p>] - a exibição condicional do formulário de entrada de dados em função de #EDITABLE: após a entrada de dados, é geralmente mais claro para o visitante não se exibir o formulário completo mas apenas as mensagens de sucesso. #EDITABLE serve para isso.
 
Dica: É possível que queiramos colocar um loop BOUCLE no formulário (para exibir os campos de um select a partir da base, por exemplo). O uso de #EDITABLE e desse loop gera um erro. A solução é incluir um loop CONDITION como mostra o exemplo a seguir:
    [<p class='formulaire_ok'>(#ENV*{message_ok})</p>]
    [<p class='formulaire_erreur'>(#ENV*{message_erreur})</p>]
    <BOUCLE_editable(CONDITION){si #ENV{editable}|oui}>
            <form action='#ENV{action}' method='post'>
                    #ACTION_FORMULAIRE{#ENV{action}}
                   <BOUCLE_article(ARTICLES){0,1}>#TITRE</BOUCLE_article>
             <label>Seu e-mail</label>
                    [<span class='erreur'>(#ENV**{erreurs}|table_valeur{email})</span>]
                    <input type='text' name='email' value='#ENV{email}' />
                    <br />
                    <label>Sua mensagem</label>
                    [<span class='erreur'>(#ENV**{erreurs}|table_valeur{message})</span>]
                    <textarea name='message'>#ENV{message}</textarea>
                    <input type='submit' name='ok' value='ok' />
            </form>
    </BOUCLE_editable>
Fim! Você pode usar o seu formulário de contato.
O bonus: formulários ajax simplificados
Você deseja que a interação entre o seu formulário e o visitante seja mais rápida e não dependa do carregamento completo da página a cada erro ou na validação?
Será necessário que o seu formulário seja implementado em AJAX. Normalmente é aqui que a dificuldade surge; este tipo de implementação costuma ser longa e trabalhosa. Mas isto é simplificado pelo formalismo CVT, que lhe oferece mecanismos automatizados para a ajaxização dos seus formulários
Para isso, basta colocar o seu formulário dentro de uma div com a classe ajax:
<div class='ajax'>
#FORMULAIRE_CONTACT
</div>
É isso!
Para ir além
-  Este exemplo não produz um formulário bonito. Para um resultado mais estético, semântico e acessível, não hesite a usar as recomendações de estruturas de Structure HTML des formulaires de SPIP para todos os seus formulários SPIP
-  Saber tudo sobre a função charger() : La fonction charger() des formulaires CVT
-  Saber tudo sobre a função verifier()  : La fonction verifier() des formulaires CVT
-  Saber tudo sobre a função traiter() : La fonction traiter() des formulaires CVT