Intereting Posts
wp_login_form () игнорирование логического действия login_form Создание уникального идентификационного номера с префиксом при регистрации или покупке определенного продукта Лучший способ настроить «nav-menu-template.php» для добавления <input>, если «link_before» – «checkbox», Связь между настраиваемыми типами сообщений, как если бы они были таксономиями? Получить шаблонную часть на основе пользовательского таксономического термина Проблема пространства имен spl_autoload в администраторе WordPress Как разместить свою форму комментариев над комментариями? Обновить подпись для изображений галереи метабокса Плагин: Почтовый заказ – как он работает? Сортировка записей по дате – get_blogs_of_user_id () Как установить количество сообщений для отображения в архиве Как скрыть сообщение Как предотвратить добавление новых терминов в пользовательскую таксономию? Проблема с метафункцией Замораживание WP_Query

Разработка защищенной формы редактирования переднего конца

Я хочу добавить функциональность редактирования переднего конца на один из моих сайтов WordPress. Я нашел несколько плагинов, которые это делают, но они не соответствуют всем моим потребностям, поэтому я решил адаптировать существующее решение для разработки своего собственного плагина, который вернется с помощью короткого кода в форме редактирования переднего конца. Мой плагин работает, я могу редактировать и сохранять сообщения, но я не могу решить предупреждение, и у меня пока нет достаточных знаний, чтобы сделать этот плагин более безопасным . Какие-либо предложения?

Предупреждение:

Предупреждение: невозможно изменить информацию заголовка – уже отправленные заголовки (вывод начат с … / wp-content / plugins / front-post-edit.php: 139) в … / wp-includes / pluggable.php в строке 1228

PS Строка 139 – последняя строка моего плагина (строка без кода).

Мой код плагина:

<?php /* * Plugin Name: Front Post Editor * */ add_shortcode( 'front_post_edit', 'post_shortcode' ); function post_shortcode() { return getForm(); } function getForm() { if ( !is_user_logged_in()) { echo '<p class="alert-box notice">You must be <a href="' . esc_url( wp_login_url( get_permalink() ) ) . '" title="Login">logged in</a>!'; } else { if( 'POST' == $_SERVER['REQUEST_METHOD'] && !empty( $_POST['action'] ) && $_POST['action'] == "edit_post" && isset($_POST['postid'])) { $post_to_edit = array(); $post_to_edit = get_post($_POST['postid']); /* these are the fields that we are editing in the form below */ $title = $_POST['item_title']; $description = $_POST['item_description']; $category = $_POST['item_category']; $location = $_POST['item_location']; $location2 = $_POST['item_location2']; /* this code will save the title and description into the post_to_edit array */ $post_to_edit->post_title = $title; $post_to_edit->post_content = $description; /* this code is a must */ $pid = wp_update_post($post_to_edit); /* save taxonomies: post ID, form field name, taxonomy name, if it appends(true) or rewrite(false) */ wp_set_post_terms($pid, array($_POST['item_category']),'category',false); wp_set_post_terms($pid, array($_POST['item_location']),'location',false); /* update custom fields with the new info */ update_post_meta($pid, 'item_location2', $location2); /* redirect user after done editing */ wp_redirect( home_url( '/myposts' ) ); } /* get post to edit */ $post_to_edit = get_post($_POST['postid']); /* get this post's category taxonomy term id */ $term_name = strip_tags( get_the_term_list( $post_to_edit->ID, 'category', '', ', ', '' ) ); $term_obj = get_term_by('name', $term_name, 'category'); $term_id = $term_obj->term_id; /* array for wp_dropdown_category to display with the current post category selected by default */ $args_cat = array( 'selected' => $term_id, 'name' => 'item_category', 'class' => 'postform', 'tab_index' => 10, 'depth' => 2, 'hierarchical' => 1, 'taxonomy' => 'category', 'hide_empty' => false ); /* get this post's location taxonomy term id */ $term_name2 = strip_tags( get_the_term_list( $post_to_edit->ID, 'location', '', ', ', '' ) ); $term_obj2 = get_term_by('name', $term_name2, 'location'); $term_id2 = $term_obj2->term_id; $args_loc = array( 'selected' => $term_id2, 'name' => 'item_location', 'class' => 'postform', 'tab_index' => 10, 'depth' => 2, 'hierarchical' => 1, 'taxonomy' => 'location', 'hide_empty' => false ); ?> <!-- EDIT FORM --> <form id="edit_post" name="edit_post" method="post" action="" enctype="multipart/form-data"> <!-- post name --> <fieldset name="item_title"> <label for="item_title">Item title:</label><br /> <input type="text" id="item_title" value="<?php echo $post_to_edit->post_title; ?>" tabindex="5" name="item_title" /> </fieldset> <!-- post Content --> <fieldset class="item_description"> <label for="item_description">Item description:</label><br /> <textarea id="item_description" tabindex="15" name="item_description"><?php echo $post_to_edit->post_content; ?></textarea> </fieldset> <!-- post Category --> <fieldset id="item_category"> <label for="item_category">Item category:</label> <?php wp_dropdown_categories( $args_cat ); ?> </fieldset> <!-- post Location --> <fieldset id="item_location"> <label for="item_location">Item location:</label> <?php wp_dropdown_categories( $args_loc ); ?> </fieldset> <!-- custom fields --> <fieldset class="item_location2"> <label for="item_location2">Location 2:</label><br /> <input type="text" value="<?php echo get_post_meta($post_to_edit->ID,'item_location2', true); ?>" id="item_location2" tabindex="20" name="item_location2" /> </fieldset> <!-- submit button --> <fieldset class="submit"> <input type="submit" value="Save Post" tabindex="40" id="submit" name="submit" /> </fieldset> <input type="hidden" name="postid" value="<?php echo $post_to_edit->ID; ?>" /> <!-- DONT REMOVE OR CHANGE --> <input type="hidden" name="action" value="edit_post" /> <!-- DONT REMOVE OR CHANGE --> <input type="hidden" name="change_cat" value="" /> <!-- DONT REMOVE OR CHANGE --> <?php // wp_nonce_field( 'new-post' ); ?> </form> <!-- END OF FORM --> <?php } ?><!-- user is logged in --> <?php } ?><!-- getForm --> 

Кнопка « Редактировать» была добавлена ​​в нижний колонтитул каждой записи, сгенерированной циклом с помощью этой формы:

 <form class="edit-post" action="<?php echo home_url( '/edit'); ?>" method="post"> <input type="hidden" name="postid" value="<?php the_ID(); ?>" /> <input type="submit" value="Edit" /> </form> 

Из кода кажется, что ваше предупреждение возникает из-за слишком быстрого перенаправления. перенаправления должны выполняться, как правило, не позднее, чем действие init. И после перенаправления вы должны умереть () (я не думаю, что wp_redirect делает это для вас)

Что касается безопасности, недостаточно проверить, что пользователь вошел в систему, вам нужно проверить, есть ли у него возможность редактировать сообщение, что-то вроде if current_user_can('edit_post',$post_id) . Вы должны проверить это как на стороне интерфейса, так и на стороне сервера. просто потому, что вы не показываете способность к хакеру, не означает, что он не будет создавать специальный HTTP-запрос для изменения сообщения, если у вас нет защиты на стороне сервера.

После некоторых исследований и исследований я отказался от подхода, описанного в моем вопросе, и действительно понял, как добавить функциональность редактирования переднего конца, используя решение @TheDeadMedic. Теперь у меня есть только два вопроса :

1) Есть ли лучший способ использовать / установить идентификатор сообщения и дату публикации? Я использовал для этих двух скрытых входов: foo_id и foo_date .

2) Насколько безопасна связь между формами?

Это форма, которая получает идентификатор сообщения в переменную «postid» и передает ее на страницу «post-form»:

 <form action="<?php echo home_url( '/post-form'); ?>" method="post"> <input type="hidden" name="postid" value="<?php the_ID(); ?>" /> <input type="submit" value="Edit" /> </form> <?php 

Это форма интерфейса для публикации сообщений редактирования (добавленный мной код отмечен // MY CODE ):

 class WPSE_Submit_From_Front { const NONCE_VALUE = 'front_end_new_post'; const NONCE_FIELD = 'fenp_nonce'; protected $pluginPath; protected $pluginUrl; protected $errors = array(); protected $data = array(); function __construct() { $this->pluginPath = plugin_dir_path( __file__ ); $this->pluginUrl = plugins_url( '', __file__ ); add_action( 'wp_enqueue_scripts', array( $this, 'addStyles' ) ); add_shortcode( 'post_from_front', array( $this, 'shortcode' ) ); // Listen for the form submit & process before headers output add_action( 'template_redirect', array( $this, 'handleForm' ) ); } function addStyles() { wp_enqueue_style( 'submitform-style', "$this->pluginUrl/submitfromfront.css" ); } /** * Shortcodes should return data, NOT echo it. * * @return string */ function shortcode() { if ( ! current_user_can( 'publish_posts' ) ) return sprintf( '<p>Please <a href="%s">login</a> to post links.</p>', esc_url( wp_login_url( get_permalink() ) ) ); elseif ( $this->isFormSuccess() ) return '<p class="success">Nice one, post created.</p>'; else return $this->getForm(); } /** * Process the form and redirect if sucessful. */ function handleForm() { if ( ! $this->isFormSubmitted() ) return false; // http://php.net/manual/en/function.filter-input-array.php $data = filter_input_array( INPUT_POST, array( // MY CODE 'foo_id' => FILTER_DEFAULT, 'foo_date' => FILTER_DEFAULT, // END MY CODE 'postTitle' => FILTER_DEFAULT, 'postContent' => FILTER_DEFAULT, 'location2' => FILTER_DEFAULT, )); $data = wp_unslash( $data ); $data = array_map( 'trim', $data ); // You might also want to more aggressively sanitize these fields // By default WordPress will handle it pretty well, based on the current user's "unfiltered_html" capability $data['postTitle'] = sanitize_text_field( $data['postTitle'] ); $data['postContent'] = wp_check_invalid_utf8( $data['postContent'] ); $data['location2'] = sanitize_text_field( $data['location2'] ); $this->data = $data; if ( ! $this->isNonceValid() ) $this->errors[] = 'Security check failed, please try again.'; if ( ! $data['postTitle'] ) $this->errors[] = 'Please enter a title.'; if ( ! $data['postContent'] ) $this->errors[] = 'Please enter the content.'; if ( ! $this->errors ) { $post_id = wp_insert_post( array( // MY CODE 'ID' => $data['foo_id'], 'post_date' => $data['foo_date'], // END MY CODE 'post_title' => $data['postTitle'], 'post_content' => $data['postContent'], 'post_status' => 'publish', )); if ( $post_id ) { add_post_meta( $post_id, 'location2', $data['location2'] ); // Redirect to avoid duplicate form submissions wp_redirect( add_query_arg( 'success', 'true' ) ); exit; } else { $this->errors[] = 'Whoops, please try again.'; } } } /** * Use output buffering to *return* the form HTML, not echo it. * * @return string */ function getForm() { // MY CODE if( 'POST' == $_SERVER['REQUEST_METHOD'] && isset( $_POST['postid'] ) ) { $post_to_edit = array(); $post_to_edit = get_post( $_POST['postid'] ); $this->data['foo_id'] = $post_to_edit->ID; $this->data['foo_date'] = $post_to_edit->post_date; $this->data['item_name'] = $post_to_edit->post_title; $this->data['item_description'] = $post_to_edit->post_content; } // END MY CODE ob_start(); ?> <div id ="frontpostform"> <?php foreach ( $this->errors as $error ) : ?> <p class="error"><?php echo $error ?></p> <?php endforeach ?> <form id="formpost" method="post"> <fieldset> <label for="postTitle">Post Title</label> <input type="text" name="postTitle" id="postTitle" value="<?php // "Sticky" field, will keep value from last POST if there were errors if ( isset( $this->data['postTitle'] ) ) echo esc_attr( $this->data['postTitle'] ); ?>" /> </fieldset> <fieldset> <label for="postContent">Content</label> <textarea name="postContent" id="postContent" rows="10" cols="35" ><?php if ( isset( $this->data['postContent'] ) ) echo esc_textarea( $this->data['postContent'] ); ?></textarea> </fieldset> <fieldset> <label for="location2">Location 2</label> <input type="text" name="location2" id="location2" title="Location 2 (opțional)" value="<?php // "Sticky" field, will keep value from last POST if there were errors if ( isset( $this->data['location2'] ) ) echo esc_attr( $this->data['location2'] ); ?>" /> </fieldset> <fieldset> // MY CODE <input type="hidden" name="foo_id" id="foo_id" value="<?php // "Sticky" field, will keep value from last POST if there were errors if ( isset( $this->data['foo_id'] ) ) echo esc_attr( $this->data['foo_id'] ); ?>" /> <input type="hidden" name="foo_date" id="foo_date" value="<?php // "Sticky" field, will keep value from last POST if there were errors if ( isset( $this->data['foo_date'] ) ) echo esc_attr( $this->data['foo_date'] ); ?>" /> // END MY CODE <button type="submit" name="submitForm" >Create Post</button> </fieldset> <?php wp_nonce_field( self::NONCE_VALUE , self::NONCE_FIELD ) ?> </form> </div> <?php return ob_get_clean(); } /** * Has the form been submitted? * * @return bool */ function isFormSubmitted() { return isset( $_POST['submitForm'] ); } /** * Has the form been successfully processed? * * @return bool */ function isFormSuccess() { return filter_input( INPUT_GET, 'success' ) === 'true'; } /** * Is the nonce field valid? * * @return bool */ function isNonceValid() { return isset( $_POST[ self::NONCE_FIELD ] ) && wp_verify_nonce( $_POST[ self::NONCE_FIELD ], self::NONCE_VALUE ); } } new WPSE_Submit_From_Front;