Как добавить на сайт форму добавления записей для пользователей, чтобы сразу создался черновик

Как добавить на сайт форму добавления записей для пользователей, чтобы сразу создался черновик

в файл functions.php (уберите пробелы в тегах скрипта)


// 1. Регистрация маршрута REST API
add_action( 'rest_api_init', function () {
    register_rest_route( 'russia247/v1', '/submit-draft', array(
        'methods'             => 'POST',
        'callback'            => 'handle_guest_news_submission',
        'permission_callback' => '__return_true',
    ) );
} );

// 2. Функция обработки данных формы
function handle_guest_news_submission( WP_REST_Request $request ) {
    $params = $request->get_json_params();

    // Защита от ботов (Honeypot)
    if ( ! empty( $params['website'] ) ) {
        return new WP_REST_Response( array( 'success' => true ), 200 );
    }

    // Очистка данных
    $author_name   = sanitize_text_field( $params['authorName'] ?? '' );
    $email         = sanitize_email( $params['email'] ?? '' );
    $title         = sanitize_text_field( $params['title'] ?? '' );
    $summary       = sanitize_textarea_field( $params['summary'] ?? '' );
    $content       = sanitize_textarea_field( $params['content'] ?? '' );
    $images_raw    = sanitize_textarea_field( $params['images'] ?? '' );

    // Проверки
    if ( empty( $author_name ) || empty( $email ) || empty( $title ) || empty( $content ) ) {
        return new WP_Error( 'missing_fields', 'Заполните обязательные поля', array( 'status' => 400 ) );
    }
    if ( ! is_email( $email ) ) {
        return new WP_Error( 'invalid_email', 'Некорректный email', array( 'status' => 400 ) );
    }
    if ( strlen( $content ) < 100 ) {
        return new WP_Error( 'short_content', 'Текст слишком короткий', array( 'status' => 400 ) );
    }

    // Формирование красивого контента для админки
    $post_content = '';

    // 1. Имя и Email автора
    $post_content .= "<p><strong>Предложил:</strong> " . esc_html( $author_name ) . " (" . esc_html( $email ) . ")</p>\n";
    $post_content .= "<hr>\n";

    // 2. Лид (аннотация)
    if ( ! empty( $summary ) ) {
        $post_content .= "<p><strong>Аннотация:</strong><br>" . nl2br( esc_html( $summary ) ) . "</p>\n";
        $post_content .= "<hr>\n";
    }

    // 3. Ссылки на изображения
    $images_array = array_filter( array_map( 'trim', explode( "\n", $images_raw ) ) );
    if ( ! empty( $images_array ) ) {
        $post_content .= "<p><strong>Ссылки на изображения:</strong></p>\n<ul>\n";
        foreach ( $images_array as $img ) {
            if ( filter_var( $img, FILTER_VALIDATE_URL ) ) {
                $post_content .= "<li>" . esc_url( $img ) . "</li>\n";
            }
        }
        $post_content .= "</ul>\n";
        $post_content .= "<hr>\n";
    }

    // 4. Основной текст статьи
    $post_content .= "<p><strong>Текст статьи:</strong></p>\n" . wpautop( esc_html( $content ) );

    // Создание черновика
    $post_id = wp_insert_post( array(
        'post_title'    => wp_strip_all_tags( $title ),
        'post_content'  => $post_content,
        'post_status'   => 'draft',
        'post_author'   => 0,
        'post_category' => array( get_option( 'default_category' ) ),
    ) );

    if ( is_wp_error( $post_id ) ) {
        return new WP_Error( 'db_error', 'Ошибка базы данных', array( 'status' => 500 ) );
    }

    // Сохраняем данные автора в мета-полях (для удобства сортировки или плагинов)
    update_post_meta( $post_id, '_guest_author_name', $author_name );
    update_post_meta( $post_id, '_guest_author_email', $email );

    return new WP_REST_Response( array( 
        'success' => true, 
        'message' => 'Новость успешно отправлена на модерацию.' 
    ), 200 );
}

// 3. Передача актуального ключа безопасности (nonce) для избежания ошибки куки
add_action( 'wp_footer', function() {
    ?>
    < script>
        window.russia247FormData = {
            apiUrl: '<?php echo esc_url_raw( rest_url( 'russia247/v1/submit-draft' ) ); ?>',
            nonce: '<?php echo wp_create_nonce( 'wp_rest' ); ?>'
        };
    </ script>
    <?php
} );

на сайте вставляем код (уберите пробелы в тегах стилей и скрипта)

<!-- Кнопка вызова формы -->
<button type="button" id="openArticleModalBtn" class="modal-trigger-btn">Предложить новость</button>

<!-- Модальное окно -->
<div id="articleModal" class="modal-overlay" aria-hidden="true">
  <div class="modal-content" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
    <button type="button" class="modal-close-btn" aria-label="Закрыть окно">&times;</button>
    
    <h2 id="modalTitle">Предложить новость</h2>
    
    <div class="form-wrapper">
      <!-- Форма -->
      <form id="articleForm" novalidate>
        <div class="form-group">
          <label for="authorName">Имя (как будет указано в публикации) *</label>
          <input type="text" id="authorName" name="authorName" required minlength="2" maxlength="80">
        </div>

        <div class="form-group">
          <label for="email">Email *</label>
          <input type="email" id="email" name="email" required>
        </div>

        <div class="form-group">
          <label for="title">Заголовок *</label>
          <input type="text" id="title" name="title" required minlength="5" maxlength="200">
        </div>

        <div class="form-group">
          <label for="summary">Короткая аннотация (лид)</label>
          <input type="text" id="summary" name="summary" maxlength="300">
        </div>

        <div class="form-group">
          <label for="content">Текст *</label>
          <textarea id="content" name="content" required minlength="100" rows="10" placeholder="Минимум 100 символов."></textarea>
        </div>

        <div class="form-group">
          <label for="images">Ссылки на изображения (каждая с новой строки)</label>
          <textarea id="images" name="images" rows="3" placeholder="https://example.com/img1.jpg&#10;https://example.com/img2.jpg"></textarea>
        </div>

        <!-- Honeypot для защиты от ботов -->
        <input type="text" name="website" tabindex="-1" autocomplete="off" class="honeypot-field">

        <div class="form-group checkbox-group">
          <label class="checkbox-label">
            <input type="checkbox" name="agreeTerms" required checked>
            Я согласен с <a href="https://russia247.ru/privacy.html" target="_blank" rel="noopener">правилами публикации</a> *
          </label>
        </div>

        <div class="form-group checkbox-group">
          <label class="checkbox-label">
            <input type="checkbox" name="agreePrivacy" required checked>
            Согласен на <a href="https://russia247.ru/privacy.html" target="_blank" rel="noopener">обработку персональных данных</a> *
          </label>
        </div>

        <button type="submit" class="submit-btn">Отправить на модерацию</button>
        <div id="formStatus" class="form-status" role="status" aria-live="polite"></div>
      </form>

      <!-- Блок успешной отправки (скрыт по умолчанию) -->
      <div id="formSuccess" class="form-success-message">
        <p>Спасибо! Ваша новость отправлена на модерацию.</p>
      </div>
    </div>
  </div>
</div>

< style>
/* Кнопка вызова */
.modal-trigger-btn {
  display: inline-block;
  padding: 0 20px;
  color: #ffffff;
  border: none;
  border-radius: 4px;
  background-color: #bf0a30;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.2s;
}
.modal-trigger-btn:hover {
  background-color: #222;
}

/* Затемнение фона */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
  padding: 20px;
  box-sizing: border-box;
}
.modal-overlay.active {
  opacity: 1;
  visibility: visible;
}

/* Контент модального окна */
.modal-content {
  background-color: #ffffff;
  width: 100%;
  max-width: 800px;
  max-height: 90vh;
  overflow-y: auto;
  border-radius: 8px;
  padding: 30px;
  position: relative;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
  transform: translateY(-20px);
  transition: transform 0.3s ease;
}
.modal-overlay.active .modal-content {
  transform: translateY(0);
}

/* Кнопка закрытия */
.modal-close-btn {
  position: absolute;
  top: 15px;
  right: 20px;
  background: none;
  border: none;
  font-size: 32px;
  line-height: 1;
  color: #666666;
  cursor: pointer;
  padding: 0;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s;
}
.modal-close-btn:hover {
  color: #000000;
}

/* Обертка формы */
.form-wrapper {
  position: relative;
}

/* Стили формы */
.modal-content h2 {
  margin-top: 0;
  margin-bottom: 20px;
  font-size: 24px;
  color: #333333;
}
.form-group {
  margin-bottom: 16px;
}
.form-group label {
  display: block;
  margin-bottom: 6px;
  font-weight: 500;
  color: #333333;
  font-size: 14px;
}
.form-group input[type="text"],
.form-group input[type="email"],
.form-group textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #cccccc;
  border-radius: 4px;
  font-size: 15px;
  font-family: inherit;
  box-sizing: border-box;
  transition: border-color 0.2s;
}
.form-group input:focus,
.form-group textarea:focus {
  border-color: #0056b3;
  outline: none;
}
.checkbox-group {
  margin-top: 20px;
}
.checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-weight: 400;
  font-size: 14px;
  cursor: pointer;
}
.checkbox-label input[type="checkbox"] {
  margin-top: 3px;
  cursor: pointer;
}
.checkbox-label a {
  color: #0056b3;
  text-decoration: underline;
}
.checkbox-label a:hover {
  text-decoration: none;
}

.submit-btn {
  display: block;
  width: 100%;
  padding: 12px 20px;
  background-color: #bf0a30;
  color: #ffffff;
  border: none;
  border-radius: 4px;
  font-weight: 600;
  cursor: pointer;
  margin-top: 24px;
  transition: background-color 0.2s;
}
.submit-btn:hover {
  background-color: #222;
}
.submit-btn:disabled {
  background-color: #999;
  cursor: not-allowed;
}

.form-status {
  margin-top: 12px;
  font-size: 14px;
  text-align: center;
}
.form-status.error {
  color: #dc3545;
}

/* Скрытие honeypot */
.honeypot-field {
  position: absolute;
  left: -9999px;
  opacity: 0;
}

/* --- Скрытие формы при успешной отправке --- */
#articleForm.is-hidden {
  display: none;
}

/* --- Сообщение об успешной отправке --- */
.form-success-message {
  display: none;
  text-align: center;
  padding: 40px 20px;
}
.form-success-message.is-visible {
  display: block;
  animation: fadeInUp 0.4s ease forwards;
}
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.form-success-message p {
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 0;
  line-height: 1.4;
}

/* Адаптивность для мобильных */
@media (max-width: 600px) {
  .modal-content {
    padding: 20px;
    max-height: 95vh;
  }
  .modal-close-btn {
    top: 10px;
    right: 10px;
  }
}
</ style>

< script>
document.addEventListener('DOMContentLoaded', function() {
  const modal = document.getElementById('articleModal');
  const openBtn = document.getElementById('openArticleModalBtn');
  const closeBtn = document.querySelector('.modal-close-btn');
  const form = document.getElementById('articleForm');
  const statusDiv = document.getElementById('formStatus');
  const formSuccess = document.getElementById('formSuccess');

  if (!openBtn || !modal || !form) return;

  // Открытие модального окна
  openBtn.addEventListener('click', function() {
    modal.classList.add('active');
    modal.setAttribute('aria-hidden', 'false');
    document.body.style.overflow = 'hidden';
  });

  // Закрытие модального окна и сброс формы
  function closeModal() {
    modal.classList.remove('active');
    modal.setAttribute('aria-hidden', 'true');
    document.body.style.overflow = '';
    
    // Сбрасываем состояние с небольшой задержкой для плавности
    setTimeout(() => {
      form.reset();
      form.classList.remove('is-hidden');
      formSuccess.classList.remove('is-visible');
      statusDiv.textContent = '';
      statusDiv.className = 'form-status';
      
      form.agreeTerms.checked = true;
      form.agreePrivacy.checked = true;
    }, 300);
  }

  closeBtn.addEventListener('click', closeModal);

  modal.addEventListener('click', function(e) {
    if (e.target === modal) {
      closeModal();
    }
  });

  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape' && modal.classList.contains('active')) {
      closeModal();
    }
  });

  // Обработка отправки формы
  form.addEventListener('submit', async function(e) {
    e.preventDefault();
    statusDiv.textContent = '';
    statusDiv.className = 'form-status';

    if (form.website && form.website.value) {
      return; 
    }

    if (!form.checkValidity()) {
      statusDiv.textContent = 'Пожалуйста, заполните все обязательные поля корректно.';
      statusDiv.classList.add('error');
      return;
    }

    const submitBtn = form.querySelector('.submit-btn');
    submitBtn.disabled = true;
    submitBtn.textContent = 'Отправка...';

    const formData = {
      authorName: form.authorName.value.trim(),
      email: form.email.value.trim().toLowerCase(),
      title: form.title.value.trim(),
      summary: form.summary.value.trim(),
      content: form.content.value,
      images: form.images.value,
      agreeTerms: form.agreeTerms.checked,
      agreePrivacy: form.agreePrivacy.checked,
      website: form.website ? form.website.value : ''
    };

    try {
      const apiData = window.russia247FormData || {};
      const apiUrl = apiData.apiUrl || '/wp-json/russia247/v1/submit-draft';
      const apiNonce = apiData.nonce || '';

      const response = await fetch(apiUrl, {
        method: 'POST',
        headers: { 
          'Content-Type': 'application/json',
          'X-WP-Nonce': apiNonce
        },
        body: JSON.stringify(formData)
      });

      const result = await response.json();

      if (!response.ok) {
        throw new Error(result.message || 'Ошибка сервера: ' + response.status);
      }

      // Успешная отправка: скрываем форму, показываем сообщение
      form.classList.add('is-hidden');
      formSuccess.classList.add('is-visible');

    } catch (error) {
      statusDiv.textContent = 'Ошибка: ' + error.message;
      statusDiv.classList.add('error');
    } finally {
      submitBtn.disabled = false;
      submitBtn.textContent = 'Отправить на модерацию';
    }
  });
});
</ script>

 

guest

Другие сообщения форума

Закрыть меню