Desarrollo de Plugins WordPress - Mensaje de Headers Already Sent
Estoy desarrollando plugins para WordPress. Cuando activo mi plugin, recibo el siguiente mensaje:
El plugin generó 293 caracteres de salida inesperada durante la activación. Si observa mensajes de "headers already sent", problemas con feeds de sindicación u otros problemas, intente desactivar o eliminar este plugin.
El plugin funciona muy bien pero no sé por qué estoy recibiendo este mensaje. Mi plugin es: http://wordpress.org/extend/plugins/facebook-send-like-button/

Esto normalmente es causado por espacios o saltos de línea antes de la etiqueta de apertura <?php
o después de la etiqueta de cierre ?>
.
Consulta esta página para ver algunas soluciones: ¿Cómo resuelvo el problema de advertencia "Headers already sent"?
ACTUALIZACIÓN
Después de examinar el código de tu plugin, noté que no tienes una etiqueta de cierre de PHP. En la última línea, añade ?>

Los archivos PHP no necesitan la etiqueta de cierre ?>
. De hecho, una forma de garantizar que no causará problemas de Headers already sent
es omitir la etiqueta de cierre.

Este era mi problema. Tenía varias líneas en blanco después de mi etiqueta de cierre ?>
.

No recomiendo usar una etiqueta de cierre PHP. Es una mala práctica que lleva a los tipos de problemas mencionados en la publicación original, y va en contra de los estándares de codificación del núcleo de WordPress (ver https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#remove-trailing-spaces)

Mi suposición es que recibes un error de PHP, que genera salida antes de que se envíen las cabeceras. Si tienes E_NOTICE
habilitado, llamar a $_POST['foo']
puede generar un "Notice: variable indefinida" si esa variable no está definida.
Mejor práctica: nunca asumas nada sobre las variables GET, POST, COOKIE y REQUEST. Siempre verifica primero usando isset()
o empty()
.
if ( isset( $_POST['foo'] ) ) {
$foo = (string) $_POST['foo'];
// aplica más saneamientos aquí si es necesario
}

Al inicio de tu función de activación coloca un ob_start();
y al final un trigger_error(ob_get_contents(),E_USER_ERROR);
Luego intenta activar tu plugin, y podrás ver cuáles son realmente los '293 caracteres de salida inesperada generados'. A partir de ahí, depurar esto será más fácil (ya sea eliminando caracteres de nueva línea o resolviendo algunos errores).

Sé que esta es una pregunta antigua y que tiene una respuesta aceptada. Hay muchas respuestas que cubren lo que el problema de activación podría ser potencialmente. Sin embargo, ninguna de las respuestas llega realmente al problema central de CÓMO depurar problemas con la activación de plugins.
Si vas a desarrollar plugins para WP, lo mejor es usar las herramientas adecuadas para el trabajo. Una de ellas es Debug Bar. Este es un plugin que te ayuda a depurar problemas en WP. Si eres un desarrollador de plugins, debería estar en tu caja de herramientas.
Debug Bar tiene varios complementos - plugins para el plugin, por así decirlo. Uno de ellos es Debug Bar Plugin Activation, que te mostrará el error PHP generado cuando el plugin se activa. Una vez que sepas cuál es el error PHP que causa que se envíen las cabeceras, entonces sabrás dónde necesitas buscar para corregirlo. Créeme, saber cuál es el error puede ahorrarte mucho tiempo en lugar de intentar averiguar qué podría ser el error.

No estoy completamente seguro de que este sea el problema, pero estoy bastante convencido.
Necesitas usar un callback válido como segundo argumento en register_activation_hook()
:
register_activation_hook(__FILE__,'twl_tablo_olustur');
Por lo que puedo ver, no has definido twl_tablo_olustur()
en ningún lugar. Esto ciertamente explicaría la salida inesperada (error de PHP generado al intentar llamar a una función inexistente), y explicaría por qué funciona bien en todas las demás circunstancias.

Suelo recibir estos mensajes con frecuencia cuando muestro mensajes de depuración de plugins o temas, especialmente cuando imprimo contenido antes de que se llame a wp_header.
Si estás imprimiendo cualquier carácter, entonces creo (podría estar equivocado aquí) que hay una declaración implícita de cabeceras, por lo que cuando ocurre la llamada normal a header(), obtienes el error ya que no puedes tener 2 declaraciones de cabeceras.
Puedes usar ob_start() para almacenar en búfer la salida, lo que debería eliminar el error - echa un vistazo a los comentarios aquí: http://php.net/manual/en/function.header.php

Observando la última revisión del plugin (381724), el problema es demasiados espacios.
Cada vez que quieras crear esta estructura:
function blabla(){
<= espacio
algo...
}
en tu código usa TABULADORES y no espacios.
Aquí está tu código donde reemplacé todos los espacios con tabuladores y no obtengo ningún mensaje al activar:
<?php
/*
Plugin Name: Facebook Send Button By Teknoblogo.com
Plugin URI: http://www.teknoblogo.com/facebook-gonder-butonu-eklenti
Description: Añade los botones de Enviar y Me gusta de Facebook a tus publicaciones. Autor: <a href="http://www.teknoblogo.com">teknoblogo.com</a>
Version: 1.3
Author: Eray Alakese
Author URI: http://www.teknoblogo.com
License: GPL2
*/
wp_register_script('fgb_script', "http://connect.facebook.net/en_US/all.js#xfbml=1");
wp_enqueue_script('fgb_script');
function fgb_ayarlari_yap()
{
add_option('fgb_yer', 'u');
add_option('fgb_buton', 'snl');
add_option('fgb_manual', 'hayir');
}
register_activation_hook( __FILE__, 'fgb_ayarlari_yap' );
function fgb_ayarlari_sil()
{
delete_option('fgb_yer');
delete_option('fgb_buton');
delete_option('fgb_manual');
}
register_deactivation_hook( __FILE__, 'fgb_ayarlari_sil' );
function fgb_ekle($content)
{
$fgb_yer = get_option('fgb_yer');
$fgb_buton_opt = get_option('fgb_buton');
$fgb_manual = get_option('fgb_manual');
$fgb_perma = rawurlencode(get_permalink());
$fgb_send_button = "<fb:send href=\"$fgb_perma\" font=\"\"></fb:send>";
$fgb_like_button = "<fb:like href=\"$fgb_perma\" send=\"false\" width=\"450\" show_faces=\"true\" font=\"\"></fb:like>";
$fgb_snl_button = "<fb:like href=\"$fgb_perma\" send=\"true\" width=\"450\" show_faces=\"true\" font=\"\"></fb:like>";
if($fgb_buton_opt == "send")
{
$fgb_buton = $fgb_send_button;
}
elseif($fgb_buton_opt == "like")
{
$fgb_buton = $fgb_like_button;
}
elseif($fgb_buton_opt == "snl")
{
$fgb_buton = $fgb_snl_button;
}
else
{
echo "¡No se pudo obtener el tipo de botón!";
}
if ($fgb_manual=="hayir"){
if ($fgb_yer == "u")
{
$content = $fgb_buton."<br />".$content;
}
elseif ($fgb_yer == "a")
{
$content = $content."<br />".$fgb_buton;
}
return $content;
}
elseif($fgb_manual=="evet"){
echo $fgb_buton;
}
}
if (get_option('fgb_manual')=="hayir"){ add_filter( "the_content", "fgb_ekle" ); }
add_action('admin_menu', 'fgb_admin_menu');
function fgb_admin_menu() {
add_options_page('Facebook Send Button', 'Facebook Send Button', 'manage_options', 'fgb', 'fgb_admin_options');
}
function fgb_admin_options() {
if (!current_user_can('manage_options')) {
wp_die( __('No tienes suficientes permisos para acceder a esta página.') );
}
echo '<div class="wrap">';
?>
<h2>Botones de Enviar y Me gusta de Facebook</h2>
<?
if($_POST["fgb_gonder"])
{
echo "<h3>guardado</h3>";
update_option('fgb_yer', $_POST["fgb_yer"]);
update_option('fgb_buton', $_POST["fgb_buton"]);
update_option('fgb_manual', $_POST["fgb_manual"]);
$fgb_admin_yer = get_option('fgb_yer');
$fgb_admin_buton = get_option('fgb_buton');
$fgb_admin_manual = get_option('fgb_manual');
}
?>
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="POST">
Mostrar botones de Facebook <select name="fgb_yer">
<option value="u" <?php if($fgb_admin_yer == "u"){echo "SELECTED";}?>>antes del contenido</option>
<option value="a" <?php if($fgb_admin_yer == "a"){echo "SELECTED";}?>>después del contenido</option>
</select> y quiero <select name="fgb_buton">
<option value="snl" <?php if($fgb_admin_buton=="snl"){echo "SELECTED";}?>>botones de enviar y me gusta juntos</option>
<option value="send" <?php if($fgb_admin_buton=="send"){echo "SELECTED";}?>>solo el botón enviar</option>
<option value="like" <?php if($fgb_admin_buton=="like"){echo "SELECTED";}?>>solo el botón me gusta</option>
</select> . <br />
<input type="radio" value="hayir" name="fgb_manual" <?php if($fgb_admin_manual=="hayir"){echo "CHECKED";}?> /> colocar botones por mí, AUTOMÁTICAMENTE <br />
<input type="radio" value="evet" name="fgb_manual" <?php if($fgb_admin_manual=="evet"){echo "CHECKED";}?> /> yo los puedo colocar, MANUALMENTE <br />
<input type="submit" class="button-primary" name="fgb_gonder" value="<?php _e('Guardar cambios') ?>" />
</form>
<br />Si usas <strong>inserción manual</strong> , debes agregar este código a tu tema:
<strong><?php if(function_exists('fgb_ekle')) { fgb_ekle(); }?></strong>
<hr />
<em>Si te gusta este plugin, por favor <a href="http://wordpress.org/extend/plugins/facebook-send-like-button/">vótalo</a>.
Autor: <a href="http://www.teknoblogo.com">Eray Alakese</a>
Puedes <a href="mailto:info@teknoblogo.com">enviarme un correo</a> para reportar errores, gracias.</em>
<?php
echo '</div>';
}

Eso no debería tener nada que ver. Los espacios y tabulaciones dentro de tus funciones son aceptables y no producen este error.

dentro de una función tienes razón, pero si la función genera salida directamente, por ejemplo: function blabla(){?> <input> <?php code... ?> generar algo <?php code.. }
entonces ese no es el caso.

@MatthewMuro: si dejas el espacio dentro de una función está bien, pero si dejas cualquier espacio en blanco/salto de línea después de las etiquetas de cierre de php ?>
entonces obtendrás el error header already send
porque esos espacios en blanco adicionales se imprimirán cuando el motor de php los analice.

Eliminas la etiqueta de cierre de PHP ( ?> ) al final de cada archivo. También eliminas todos los espacios en blanco después de la etiqueta de cierre de PHP ( ?> ).
Cuando activas el plugin, simplemente verificas si la tabla ya existe o no.
Solucioné el problema con el siguiente código:
if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
$sql = "CREATE TABLE {$table_name}(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(250),
email VARCHAR(250),
PRIMARY KEY (id)
);";
dbDelta($sql);
}
