Restore to commit 74e578279624c6045ca440a3459ebfa1f8d54191

This commit is contained in:
southseact-3d
2026-02-07 20:32:41 +00:00
commit ed67b7741b
252 changed files with 99814 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
<?php
/**
* Admin Menu Class
*
* Handles admin menu registration and page routing.
*
* @package PCFormBuilder
*/
class PCFB_Admin_Menu {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'handle_form_actions' ) );
add_action( 'wp_ajax_pcfb_add_field', array( $this, 'ajax_add_field' ) );
}
public function add_admin_menu() {
add_menu_page(
__( 'Form Builder', 'pc-form-builder-xyz123' ),
__( 'Form Builder', 'pc-form-builder-xyz123' ),
'manage_options',
'pcfb-form-builder',
array( $this, 'render_form_builder_page' ),
'dashicons-feedback',
30
);
add_submenu_page(
'pcfb-form-builder',
__( 'Form Builder', 'pc-form-builder-xyz123' ),
__( 'Form Builder', 'pc-form-builder-xyz123' ),
'manage_options',
'pcfb-form-builder',
array( $this, 'render_form_builder_page' )
);
add_submenu_page(
'pcfb-form-builder',
__( 'All Forms', 'pc-form-builder-xyz123' ),
__( 'All Forms', 'pc-form-builder-xyz123' ),
'manage_options',
'pcfb-all-forms',
array( $this, 'render_all_forms_page' )
);
add_submenu_page(
'pcfb-form-builder',
__( 'Responses', 'pc-form-builder-xyz123' ),
__( 'Responses', 'pc-form-builder-xyz123' ),
'manage_options',
'pcfb-responses',
array( $this, 'render_responses_page' )
);
}
public function render_form_builder_page() {
require_once PCFB_PLUGIN_DIR . 'admin/class-admin-helper.php';
$helper = PCFB_Admin_Helper::get_instance();
$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
if ( $form_id > 0 ) {
include PCFB_PLUGIN_DIR . 'admin/page-form-builder.php';
} else {
include PCFB_PLUGIN_DIR . 'admin/page-form-builder.php';
}
}
public function render_all_forms_page() {
include PCFB_PLUGIN_DIR . 'admin/page-all-forms.php';
}
public function render_responses_page() {
$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
$response_id = isset( $_GET['response_id'] ) ? intval( $_GET['response_id'] ) : 0;
if ( $response_id > 0 ) {
include PCFB_PLUGIN_DIR . 'admin/page-response-detail.php';
} elseif ( $form_id > 0 ) {
include PCFB_PLUGIN_DIR . 'admin/page-form-responses.php';
} else {
include PCFB_PLUGIN_DIR . 'admin/page-responses.php';
}
}
public function handle_form_actions() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( ! isset( $_POST['pcfb_action'] ) ) {
return;
}
if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'pcfb_admin_action' ) ) {
return;
}
$action = sanitize_text_field( $_POST['pcfb_action'] );
switch ( $action ) {
case 'save_form':
$this->handle_save_form();
break;
case 'delete_form':
$this->handle_delete_form();
break;
case 'toggle_status':
$this->handle_toggle_status();
break;
}
}
private function handle_save_form() {
$form_data = isset( $_POST['form'] ) ? $_POST['form'] : array();
$fields = isset( $_POST['fields'] ) ? $_POST['fields'] : array();
$handler = PC_Form_Handler::get_instance();
$form_id = $handler->save_form( $form_data, $fields );
if ( $form_id ) {
$edit_url = admin_url( 'admin.php?page=pcfb-form-builder&form_id=' . $form_id );
$shortcode = '[pcfb-form id="' . $form_id . '"]';
add_action( 'admin_notices', function() use ( $edit_url, $shortcode ) {
echo '<div class="notice notice-success is-dismissible"><p>';
echo sprintf( __( 'Form saved successfully!', 'pc-form-builder-xyz123' ) );
echo '</p><p><strong>' . esc_html__( 'Shortcode:', 'pc-form-builder-xyz123' ) . '</strong> <code onclick="this.select(); document.execCommand(\'copy\');" style="background: #f0f0f1; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 14px;">' . esc_html( $shortcode ) . '</code></p>';
echo '<p><a href="' . esc_url( $edit_url ) . '" class="button button-primary" style="margin-top: 10px;">' . esc_html__( 'Go to Form Builder', 'pc-form-builder-xyz123' ) . '</a></p></div>';
} );
wp_redirect( admin_url( 'admin.php?page=pcfb-form-builder&form_id=' . $form_id ) );
exit;
} else {
add_action( 'admin_notices', function() {
echo '<div class="notice notice-error is-dismissible"><p>';
echo esc_html__( 'Failed to save form. Please try again.', 'pc-form-builder-xyz123' );
echo '</p></div>';
} );
}
}
private function handle_delete_form() {
$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
if ( $form_id > 0 && PC_Form_Handler::delete_form( $form_id ) ) {
add_action( 'admin_notices', function() {
echo '<div class="notice notice-success is-dismissible"><p>';
echo esc_html__( 'Form deleted successfully.', 'pc-form-builder-xyz123' );
echo '</p></div>';
} );
} else {
add_action( 'admin_notices', function() {
echo '<div class="notice notice-error is-dismissible"><p>';
echo esc_html__( 'Failed to delete form. Please try again.', 'pc-form-builder-xyz123' );
echo '</p></div>';
} );
}
}
private function handle_toggle_status() {
global $wpdb;
$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
if ( $form_id > 0 ) {
$form = PC_Form_Handler::get_form_by_id( $form_id );
if ( $form ) {
$new_status = 'active' === $form->status ? 'inactive' : 'active';
$table_name = $wpdb->prefix . 'pcfb_forms';
$wpdb->update( $table_name, array( 'status' => $new_status ), array( 'id' => $form_id ) );
}
}
}
public function ajax_add_field() {
check_ajax_referer( 'pcfb_admin_nonce', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'pc-form-builder-xyz123' ) ) );
}
$field_type = isset( $_POST['field_type'] ) ? sanitize_text_field( $_POST['field_type'] ) : 'text';
$field_index = isset( $_POST['field_index'] ) ? intval( $_POST['field_index'] ) : 0;
require_once PCFB_PLUGIN_DIR . 'admin/class-admin-helper.php';
$helper = PCFB_Admin_Helper::get_instance();
ob_start();
$helper->render_new_field_item( $field_type, $field_index );
$html = ob_get_clean();
wp_send_json_success( array( 'html' => $html ) );
}
}

View File

@@ -0,0 +1,181 @@
<?php
/**
* Admin Helper Class
*
* Provides helper methods for admin pages.
*
* @package PCFormBuilder
*/
class PCFB_Admin_Helper {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
public function get_field_types() {
return array(
'text' => __( 'Text Input', 'pc-form-builder-xyz123' ),
'email' => __( 'Email', 'pc-form-builder-xyz123' ),
'name' => __( 'Name', 'pc-form-builder-xyz123' ),
'response' => __( 'Response', 'pc-form-builder-xyz123' ),
'dropdown' => __( 'Dropdown', 'pc-form-builder-xyz123' ),
'checkbox' => __( 'Checkbox', 'pc-form-builder-xyz123' ),
);
}
public function get_form_fields( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ) );
}
public function render_field_item( $field, $index = 0 ) {
$validation_rules = maybe_unserialize( $field->validation_rules );
$options = maybe_unserialize( $field->options );
$field_types = $this->get_field_types();
$field_type_label = isset( $field_types[ $field->field_type ] ) ? $field_types[ $field->field_type ] : $field->field_type;
?>
<div class="pcfb-field-item" data-field-id="<?php echo esc_attr( $field->id ); ?>" data-field-type="<?php echo esc_attr( $field->field_type ); ?>">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][id]" value="<?php echo esc_attr( $field->id ); ?>">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][field_type]" value="<?php echo esc_attr( $field->field_type ); ?>">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][field_name]" value="<?php echo esc_attr( $field->field_name ); ?>">
<div class="pcfb-field-header">
<span class="pcfb-field-type-badge"><?php echo esc_html( $field_type_label ); ?></span>
<span class="pcfb-field-name-display"><?php echo esc_html( $field->field_name ); ?></span>
<div class="pcfb-field-actions">
<button type="button" class="button button-small pcfb-toggle-field">
<span class="dashicons dashicons-arrow-up-alt2"></span>
</button>
</div>
</div>
<div class="pcfb-field-content">
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Field Label', 'pc-form-builder-xyz123' ); ?></label>
<input type="text" name="fields[<?php echo esc_attr( $index ); ?>][field_label]" value="<?php echo esc_attr( $field->field_label ); ?>" class="pcfb-field-label-input" placeholder="<?php esc_attr_e( 'Enter field label', 'pc-form-builder-xyz123' ); ?>">
</div>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Placeholder Text', 'pc-form-builder-xyz123' ); ?></label>
<input type="text" name="fields[<?php echo esc_attr( $index ); ?>][placeholder]" value="<?php echo esc_attr( $field->placeholder ); ?>" placeholder="<?php esc_attr_e( 'Optional placeholder text', 'pc-form-builder-xyz123' ); ?>">
</div>
<?php if ( 'dropdown' === $field->field_type ) : ?>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Options', 'pc-form-builder-xyz123' ); ?></label>
<textarea name="fields[<?php echo esc_attr( $index ); ?>][options]" rows="3" placeholder="<?php esc_attr_e( 'One option per line', 'pc-form-builder-xyz123' ); ?>"><?php echo ! empty( $options ) ? esc_textarea( implode( "\n", $options ) ) : ''; ?></textarea>
<p class="description"><?php esc_html_e( 'Enter each option on a new line.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php elseif ( 'checkbox' === $field->field_type ) : ?>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Checkbox Options', 'pc-form-builder-xyz123' ); ?></label>
<textarea name="fields[<?php echo esc_attr( $index ); ?>][options]" rows="3" placeholder="<?php esc_attr_e( 'One option per line', 'pc-form-builder-xyz123' ); ?>"><?php echo ! empty( $options ) ? esc_textarea( implode( "\n", $options ) ) : ''; ?></textarea>
<p class="description"><?php esc_html_e( 'Enter each checkbox option on a new line.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php endif; ?>
<div class="pcfb-form-group pcfb-validation-group">
<label class="pcfb-checkbox-label">
<input type="checkbox" name="fields[<?php echo esc_attr( $index ); ?>][validation_rules][required]" value="1" <?php checked( ! empty( $validation_rules['required'] ), true ); ?>>
<?php esc_html_e( 'Required field', 'pc-form-builder-xyz123' ); ?>
</label>
</div>
</div>
<div class="pcfb-field-footer">
<button type="button" class="button button-link-delete pcfb-delete-field"><?php esc_html_e( 'Remove Field', 'pc-form-builder-xyz123' ); ?></button>
</div>
</div>
<?php
}
public function render_new_field_item( $field_type, $index ) {
$field_types = $this->get_field_types();
$field_type_label = isset( $field_types[ $field_type ] ) ? $field_types[ $field_type ] : $field_type;
$default_labels = array(
'text' => __( 'Text Field', 'pc-form-builder-xyz123' ),
'email' => __( 'Email Address', 'pc-form-builder-xyz123' ),
'name' => __( 'Full Name', 'pc-form-builder-xyz123' ),
'response' => __( 'Your Response', 'pc-form-builder-xyz123' ),
'dropdown' => __( 'Select Option', 'pc-form-builder-xyz123' ),
'checkbox' => __( 'Checkboxes', 'pc-form-builder-xyz123' ),
);
$default_label = isset( $default_labels[ $field_type ] ) ? $default_labels[ $field_type ] : __( 'Field', 'pc-form-builder-xyz123' );
$placeholder = '';
if ( 'response' === $field_type ) {
$placeholder = __( 'Enter your response here...', 'pc-form-builder-xyz123' );
}
?>
<div class="pcfb-field-item pcfb-new-field" data-field-id="new" data-field-type="<?php echo esc_attr( $field_type ); ?>">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][id]" value="">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][field_type]" value="<?php echo esc_attr( $field_type ); ?>">
<input type="hidden" name="fields[<?php echo esc_attr( $index ); ?>][field_name]" value="">
<div class="pcfb-field-header">
<span class="pcfb-field-type-badge"><?php echo esc_html( $field_type_label ); ?></span>
<span class="pcfb-field-name-display"><?php echo esc_html( sanitize_title( $default_label ) ); ?></span>
<div class="pcfb-field-actions">
<button type="button" class="button button-small pcfb-toggle-field">
<span class="dashicons dashicons-arrow-up-alt2"></span>
</button>
</div>
</div>
<div class="pcfb-field-content">
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Field Label', 'pc-form-builder-xyz123' ); ?></label>
<input type="text" name="fields[<?php echo esc_attr( $index ); ?>][field_label]" value="<?php echo esc_attr( $default_label ); ?>" class="pcfb-field-label-input" placeholder="<?php esc_attr_e( 'Enter field label', 'pc-form-builder-xyz123' ); ?>">
</div>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Placeholder Text', 'pc-form-builder-xyz123' ); ?></label>
<input type="text" name="fields[<?php echo esc_attr( $index ); ?>][placeholder]" value="<?php echo esc_attr( $placeholder ); ?>" placeholder="<?php esc_attr_e( 'Optional placeholder text', 'pc-form-builder-xyz123' ); ?>">
</div>
<?php if ( 'dropdown' === $field_type ) : ?>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Options', 'pc-form-builder-xyz123' ); ?></label>
<textarea name="fields[<?php echo esc_attr( $index ); ?>][options]" rows="3" placeholder="<?php esc_attr_e( 'One option per line', 'pc-form-builder-xyz123' ); ?>"></textarea>
<p class="description"><?php esc_html_e( 'Enter each option on a new line.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php elseif ( 'checkbox' === $field_type ) : ?>
<div class="pcfb-form-group">
<label><?php esc_html_e( 'Checkbox Options', 'pc-form-builder-xyz123' ); ?></label>
<textarea name="fields[<?php echo esc_attr( $index ); ?>][options]" rows="3" placeholder="<?php esc_attr_e( 'One option per line', 'pc-form-builder-xyz123' ); ?>"></textarea>
<p class="description"><?php esc_html_e( 'Enter each checkbox option on a new line.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php endif; ?>
<div class="pcfb-form-group pcfb-validation-group">
<label class="pcfb-checkbox-label">
<input type="checkbox" name="fields[<?php echo esc_attr( $index ); ?>][validation_rules][required]" value="1">
<?php esc_html_e( 'Required field', 'pc-form-builder-xyz123' ); ?>
</label>
</div>
</div>
<div class="pcfb-field-footer">
<button type="button" class="button button-link-delete pcfb-delete-field"><?php esc_html_e( 'Remove Field', 'pc-form-builder-xyz123' ); ?></button>
</div>
</div>
<?php
}
}
if ( ! class_exists( 'PCFB_Field_Icons' ) ) {
class PCFB_Field_Icons {
private static $icons = array(
'text' => 'dashicons-text',
'email' => 'dashicons-email',
'name' => 'dashicons-admin-users',
'response' => 'dashicons-editor-quote',
'dropdown' => 'dashicons-arrow-down-alt2',
'checkbox' => 'dashicons-yes',
);
public static function get_field_icon( $type ) {
return isset( self::$icons[ $type ] ) ? self::$icons[ $type ] : 'dashicons-editor-help';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,240 @@
/**
* PC Form Builder Admin Scripts
*
* JavaScript functionality for the form builder admin interface.
*
* @package PCFormBuilder
*/
(function($) {
'use strict';
var PCFB_Admin = {
fieldIndex: 0,
deletedFields: [],
init: function() {
this.initFieldTypeButtons();
this.initFieldToggle();
this.initFieldDelete();
this.initDeleteModal();
this.initFormBuilder();
},
initFieldTypeButtons: function() {
var self = this;
$('.pcfb-add-field-btn').on('click', function(e) {
e.preventDefault();
var fieldType = $(this).data('field-type');
self.addField(fieldType);
});
},
addField: function(fieldType) {
var self = this;
var container = $('#pcfb-fields-container');
if (container.find('.pcfb-empty-fields').length > 0) {
container.find('.pcfb-empty-fields').remove();
}
var fieldIndex = this.getNextFieldIndex();
var nonce = pcfbAdminVars.nonce;
$.ajax({
url: pcfbAdminVars.ajaxurl,
type: 'POST',
data: {
action: 'pcfb_add_field',
field_type: fieldType,
field_index: fieldIndex,
nonce: nonce
},
success: function(response) {
if (response.success) {
container.append(response.data.html);
self.reindexFields();
self.initFieldToggle();
self.initFieldDelete();
self.updateLabelOnChange();
}
},
error: function() {
alert(pcfbAdminVars.i18n.confirmDeleteField);
}
});
},
getNextFieldIndex: function() {
var maxIndex = 0;
$('#pcfb-fields-container [name^="fields["]').each(function() {
var match = $(this).attr('name').match(/fields\[(\d+)\]/);
if (match && parseInt(match[1]) > maxIndex) {
maxIndex = parseInt(match[1]);
}
});
return maxIndex + 1;
},
reindexFields: function() {
var fields = $('#pcfb-fields-container .pcfb-field-item');
fields.each(function(index) {
var field = $(this);
field.find('[name^="fields["]').each(function() {
var name = $(this).attr('name');
var newName = name.replace(/fields\[\d+\]/, 'fields[' + index + ']');
$(this).attr('name', newName);
});
});
},
initFieldToggle: function() {
$('.pcfb-toggle-field').off('click').on('click', function(e) {
e.preventDefault();
$(this).closest('.pcfb-field-item').toggleClass('collapsed');
});
},
initFieldDelete: function() {
var self = this;
$('.pcfb-delete-field').off('click').on('click', function(e) {
e.preventDefault();
var fieldItem = $(this).closest('.pcfb-field-item');
var fieldId = fieldItem.data('field-id');
if (confirm(pcfbAdminVars.i18n.confirmDeleteField)) {
if (fieldId && fieldId !== 'new') {
self.deletedFields.push(fieldId);
$('<input type="hidden" name="deleted_fields[]" value="' + fieldId + '">').appendTo('#pcfb-form-builder');
}
fieldItem.fadeOut(300, function() {
$(this).remove();
self.reindexFields();
self.checkEmptyFields();
});
}
});
},
checkEmptyFields: function() {
var container = $('#pcfb-fields-container');
if (container.find('.pcfb-field-item').length === 0) {
container.html('<div class="pcfb-empty-fields"><p>' + pcfbAdminVars.i18n.fieldLabel + '</p></div>');
}
},
updateLabelOnChange: function() {
$('.pcfb-field-label-input').off('input').on('input', function() {
var label = $(this).val();
var fieldItem = $(this).closest('.pcfb-field-item');
var fieldName = fieldItem.find('.pcfb-field-name-display');
var baseName = this.getAttribute('name').match(/fields\[(\d+)\]\[field_label\]/);
if (baseName) {
var slug = label.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');
if (slug === '') {
slug = 'field_' + baseName[1];
}
fieldName.text(slug);
var hiddenName = fieldItem.find('input[name^="fields["][name$="[field_name]"]');
hiddenName.val(slug);
}
});
},
initDeleteModal: function() {
var self = this;
$(document).on('click', '.pcfb-delete-form, .pcfb-delete-form-btn, .pcfb-delete-form-link', function(e) {
if (e.target.tagName === 'BUTTON' || $(this).hasClass('pcfb-delete-form') || $(this).hasClass('pcfb-delete-form-btn') || $(this).hasClass('pcfb-delete-form-link')) {
e.preventDefault();
var formId = $(this).data('form-id');
var formName = $(this).data('form-name');
$('#pcfb-delete-form-id').val(formId);
$('#pcfb-delete-form-name').text(formName);
$('#pcfb-delete-modal').addClass('active').show();
}
});
$('.pcfb-modal-close, .pcfb-modal-cancel').on('click', function(e) {
e.preventDefault();
$('#pcfb-delete-modal').removeClass('active').hide();
});
$('#pcfb-delete-modal').on('click', function(e) {
if ($(e.target).is('#pcfb-delete-modal')) {
$(this).removeClass('active').hide();
}
});
},
initFormBuilder: function() {
var self = this;
if ($('#pcfb-fields-container').length > 0) {
$('#pcfb-fields-container').sortable({
handle: '.pcfb-field-header',
placeholder: 'pcfb-field-placeholder',
tolerance: 'pointer',
update: function() {
self.reindexFields();
}
});
}
if ($('#pcfb-sections-container').length > 0) {
$('#pcfb-sections-container').sortable({
handle: '.pcfb-section-header',
placeholder: 'pcfb-section-placeholder',
tolerance: 'pointer'
});
}
$('#pcfb-add-section').on('click', function(e) {
e.preventDefault();
self.addSection();
});
$('#pcfb-form-builder').on('submit', function(e) {
var formName = $('#form-name').val().trim();
if (!formName) {
e.preventDefault();
alert(pcfbAdminVars.i18n.fieldLabel);
$('#form-name').focus();
return false;
}
var hasRequiredFields = false;
$('.pcfb-field-item').each(function() {
if ($(this).find('[name*="[validation_rules][required]"]').is(':checked')) {
hasRequiredFields = true;
}
});
});
},
addSection: function() {
var container = $('#pcfb-sections-container');
var sectionCount = container.find('.pcfb-section-box').length;
var sectionHtml = '<div class="pcfb-section-box" data-section-id="new-' + sectionCount + '">' +
'<div class="pcfb-section-header">' +
'<span class="dashicons dashicons-menu"></span>' +
'<span class="pcfb-section-title">Section ' + (sectionCount + 1) + '</span>' +
'</div>' +
'<div class="pcfb-section-content">' +
'<input type="hidden" name="sections[' + sectionCount + '][id]" value="">' +
'<input type="hidden" name="sections[' + sectionCount + '][title]" value="Section ' + (sectionCount + 1) + '">' +
'<p class="description">Drag fields into this section or click to configure.</p>' +
'</div>' +
'</div>';
container.append(sectionHtml);
}
};
$(document).ready(function() {
PCFB_Admin.init();
});
})(jQuery);

View File

@@ -0,0 +1,195 @@
<div class="wrap pcfb-wrap">
<h1 class="wp-heading-inline">
<span class="pcfb-heading-icon dashicons dashicons-forms"></span>
<?php esc_html_e( 'All Forms', 'pc-form-builder-xyz123' ); ?>
</h1>
<a href="<?php echo admin_url( 'admin.php?page=pcfb-form-builder' ); ?>" class="page-title-action">
<span class="dashicons dashicons-plus"></span>
<?php esc_html_e( 'Add New Form', 'pc-form-builder-xyz123' ); ?>
</a>
<hr class="wp-header-end">
<?php
$forms = PC_Form_Handler::get_forms( array( 'limit' => 50, 'status' => '' ) );
$active_count = PC_Form_Handler::get_form_count( 'active' );
$inactive_count = PC_Form_Handler::get_form_count( 'inactive' );
$total_responses = 0;
foreach ( $forms as $form ) {
$total_responses += PC_Form_Handler::get_form_response_count( $form->id );
}
?>
<div class="pcfb-all-forms-page">
<div class="pcfb-stats-row">
<div class="pcfb-stat-card">
<div class="pcfb-stat-icon pcfb-stat-icon-blue">
<span class="dashicons dashicons-forms"></span>
</div>
<div class="pcfb-stat-content">
<span class="pcfb-stat-number"><?php echo esc_html( count( $forms ) ); ?></span>
<span class="pcfb-stat-label"><?php esc_html_e( 'Total Forms', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
<div class="pcfb-stat-card">
<div class="pcfb-stat-icon pcfb-stat-icon-green">
<span class="dashicons dashicons-yes-alt"></span>
</div>
<div class="pcfb-stat-content">
<span class="pcfb-stat-number"><?php echo esc_html( $active_count ); ?></span>
<span class="pcfb-stat-label"><?php esc_html_e( 'Active Forms', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
<div class="pcfb-stat-card">
<div class="pcfb-stat-icon pcfb-stat-icon-orange">
<span class="dashicons dashicons-hidden"></span>
</div>
<div class="pcfb-stat-content">
<span class="pcfb-stat-number"><?php echo esc_html( $inactive_count ); ?></span>
<span class="pcfb-stat-label"><?php esc_html_e( 'Inactive Forms', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
<div class="pcfb-stat-card">
<div class="pcfb-stat-icon pcfb-stat-icon-purple">
<span class="dashicons dashicons-pressthis"></span>
</div>
<div class="pcfb-stat-content">
<span class="pcfb-stat-number"><?php echo esc_html( $total_responses ); ?></span>
<span class="pcfb-stat-label"><?php esc_html_e( 'Total Signups', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
</div>
<?php if ( empty( $forms ) ) : ?>
<div class="pcfb-empty-state">
<span class="dashicons dashicons-forms pcfb-empty-icon"></span>
<h3><?php esc_html_e( 'No forms created yet', 'pc-form-builder-xyz123' ); ?></h3>
<p><?php esc_html_e( 'Create your first form to start collecting responses from your visitors.', 'pc-form-builder-xyz123' ); ?></p>
<a href="<?php echo admin_url( 'admin.php?page=pcfb-form-builder' ); ?>" class="button button-primary">
<?php esc_html_e( 'Create Your First Form', 'pc-form-builder-xyz123' ); ?>
</a>
</div>
<?php else : ?>
<div class="pcfb-forms-table-card">
<div class="pcfb-card-header pcfb-table-header">
<h2><?php esc_html_e( 'Your Forms', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<table class="widefat pcfb-table pcfb-forms-table">
<thead>
<tr>
<th class="column-primary"><?php esc_html_e( 'Form Name', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Shortcode', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Fields', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Signups', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Status', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Created', 'pc-form-builder-xyz123' ); ?></th>
<th class="column-actions"><?php esc_html_e( 'Actions', 'pc-form-builder-xyz123' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $forms as $form ) : ?>
<?php
$field_count = pcfb_get_field_count( $form->id );
$response_count = PC_Form_Handler::get_form_response_count( $form->id );
$edit_url = admin_url( 'admin.php?page=pcfb-form-builder&form_id=' . $form->id );
$responses_url = admin_url( 'admin.php?page=pcfb-responses&form_id=' . $form->id );
$status_class = 'active' === $form->status ? 'status-active' : 'status-inactive';
$status_text = 'active' === $form->status ? __( 'Active', 'pc-form-builder-xyz123' ) : __( 'Inactive', 'pc-form-builder-xyz123' );
?>
<tr>
<td class="column-primary">
<strong>
<a href="<?php echo esc_url( $edit_url ); ?>">
<?php echo esc_html( $form->name ); ?>
</a>
</strong>
<div class="row-actions">
<span class="edit"><a href="<?php echo esc_url( $edit_url ); ?>"><?php esc_html_e( 'Edit', 'pc-form-builder-xyz123' ); ?></a> | </span>
<span class="responses"><a href="<?php echo esc_url( $responses_url ); ?>"><?php esc_html_e( 'Responses', 'pc-form-builder-xyz123' ); ?></a> | </span>
<span class="delete"><button type="button" class="pcfb-delete-form-link" data-form-id="<?php echo esc_attr( $form->id ); ?>" data-form-name="<?php echo esc_attr( $form->name ); ?>"><?php esc_html_e( 'Delete', 'pc-form-builder-xyz123' ); ?></button></span>
</div>
<?php if ( $form->description ) : ?>
<br>
<small class="description"><?php echo esc_html( $form->description ); ?></small>
<?php endif; ?>
</td>
<td data-colname="<?php esc_attr_e( 'Shortcode', 'pc-form-builder-xyz123' ); ?>">
<code class="pcfb-shortcode" onclick="this.select(); document.execCommand('copy');" title="<?php esc_attr_e( 'Click to copy', 'pc-form-builder-xyz123' ); ?>">
[pcfb-form id="<?php echo esc_attr( $form->id ); ?>"]
</code>
</td>
<td data-colname="<?php esc_attr_e( 'Fields', 'pc-form-builder-xyz123' ); ?>">
<span class="pcfb-field-badge"><?php echo esc_html( $field_count ); ?></span>
</td>
<td data-colname="<?php esc_attr_e( 'Signups', 'pc-form-builder-xyz123' ); ?>">
<?php if ( $response_count > 0 ) : ?>
<a href="<?php echo esc_url( $responses_url ); ?>" class="pcfb-signups-link">
<span class="pcfb-signup-count"><?php echo esc_html( $response_count ); ?></span>
</a>
<?php else : ?>
<span class="pcfb-signup-count zero"><?php echo esc_html( $response_count ); ?></span>
<?php endif; ?>
</td>
<td data-colname="<?php esc_attr_e( 'Status', 'pc-form-builder-xyz123' ); ?>">
<span class="pcfb-status <?php echo esc_attr( $status_class ); ?>">
<?php echo esc_html( $status_text ); ?>
</span>
</td>
<td data-colname="<?php esc_attr_e( 'Created', 'pc-form-builder-xyz123' ); ?>">
<?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $form->created_at ) ) ); ?>
</td>
<td class="column-actions" data-colname="<?php esc_attr_e( 'Actions', 'pc-form-builder-xyz123' ); ?>">
<div class="pcfb-actions">
<a href="<?php echo esc_url( $edit_url ); ?>" class="button button-small" title="<?php esc_attr_e( 'Edit Form', 'pc-form-builder-xyz123' ); ?>">
<span class="dashicons dashicons-edit"></span>
</a>
<a href="<?php echo esc_url( $responses_url ); ?>" class="button button-small" title="<?php esc_attr_e( 'View Responses', 'pc-form-builder-xyz123' ); ?>">
<span class="dashicons dashicons-pressthis"></span>
</a>
<button type="button" class="button button-small pcfb-delete-form" data-form-id="<?php echo esc_attr( $form->id ); ?>" data-form-name="<?php echo esc_attr( $form->name ); ?>" title="<?php esc_attr_e( 'Delete Form', 'pc-form-builder-xyz123' ); ?>">
<span class="dashicons dashicons-trash"></span>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div id="pcfb-delete-modal" class="pcfb-modal" style="display: none;">
<div class="pcfb-modal-content">
<div class="pcfb-modal-header">
<h3><?php esc_html_e( 'Delete Form', 'pc-form-builder-xyz123' ); ?></h3>
<button type="button" class="pcfb-modal-close">&times;</button>
</div>
<div class="pcfb-modal-body">
<p><?php esc_html_e( 'Are you sure you want to delete this form? All responses will also be deleted. This action cannot be undone.', 'pc-form-builder-xyz123' ); ?></p>
<p><strong id="pcfb-delete-form-name"></strong></p>
</div>
<div class="pcfb-modal-footer">
<form method="post" id="pcfb-delete-form">
<?php wp_nonce_field( 'pcfb_admin_action', '_wpnonce' ); ?>
<input type="hidden" name="pcfb_action" value="delete_form">
<input type="hidden" name="form_id" id="pcfb-delete-form-id" value="">
<button type="button" class="button pcfb-modal-cancel"><?php esc_html_e( 'Cancel', 'pc-form-builder-xyz123' ); ?></button>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Delete Form', 'pc-form-builder-xyz123' ); ?></button>
</form>
</div>
</div>
</div>
</div>
<?php
function pcfb_get_field_count( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE form_id = %d", $form_id ) );
}
?>

View File

@@ -0,0 +1,199 @@
<div class="wrap pcfb-wrap">
<h1 class="wp-heading-inline">
<span class="pcfb-heading-icon dashicons dashicons-feedback"></span>
<?php esc_html_e( 'Form Builder', 'pc-form-builder-xyz123' ); ?>
</h1>
<a href="<?php echo admin_url( 'admin.php?page=pcfb-all-forms' ); ?>" class="page-title-action">
<span class="dashicons dashicons-list-view"></span>
<?php esc_html_e( 'All Forms', 'pc-form-builder-xyz123' ); ?>
</a>
<hr class="wp-header-end">
<?php
require_once PCFB_PLUGIN_DIR . 'admin/class-admin-helper.php';
$helper = PCFB_Admin_Helper::get_instance();
$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
$is_new = $form_id === 0;
if ( ! $is_new ) {
$form = PC_Form_Handler::get_form_by_id( $form_id );
if ( ! $form ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Form not found.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$fields = $helper->get_form_fields( $form_id );
$settings = maybe_unserialize( $form->settings );
} else {
$form = (object) array(
'id' => 0,
'name' => '',
'description' => '',
'status' => 'active',
'settings' => array(),
);
$fields = array();
$settings = array();
}
$field_types = $helper->get_field_types();
?>
<?php if ( ! $is_new ) : ?>
<div class="pcfb-shortcode-notice" style="background: #f0f0f1; border: 1px solid #c3c4c7; border-radius: 6px; padding: 15px 20px; margin-bottom: 20px; display: flex; align-items: center; gap: 15px;">
<span class="dashicons dashicons-shortcode" style="color: #2271b1; font-size: 24px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;"></span>
<div style="flex: 1;">
<strong style="display: block; margin-bottom: 4px;"><?php esc_html_e( 'Form Shortcode', 'pc-form-builder-xyz123' ); ?></strong>
<code onclick="this.select(); document.execCommand('copy');" style="background: #fff; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 14px; display: inline-block;">[pcfb-form id="<?php echo esc_attr( $form->id ); ?>"]</code>
<span class="description" style="display: block; margin-top: 4px; font-size: 12px;"><?php esc_html_e( 'Click the shortcode to copy it', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
<?php endif; ?>
<form method="post" id="pcfb-form-builder" class="pcfb-form-builder">
<?php wp_nonce_field( 'pcfb_admin_action', '_wpnonce' ); ?>
<input type="hidden" name="pcfb_action" value="save_form">
<input type="hidden" name="form[id]" value="<?php echo esc_attr( $form->id ); ?>">
<div class="pcfb-builder-layout">
<div class="pcfb-builder-main">
<div class="pcfb-card pcfb-form-settings-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Form Details', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<div class="pcfb-form-group">
<label for="form-name"><?php esc_html_e( 'Form Name', 'pc-form-builder-xyz123' ); ?> *</label>
<input type="text" id="form-name" name="form[name]" value="<?php echo esc_attr( $form->name ); ?>" required placeholder="<?php esc_attr_e( 'Enter form name', 'pc-form-builder-xyz123' ); ?>">
</div>
<div class="pcfb-form-group">
<label for="form-description"><?php esc_html_e( 'Description', 'pc-form-builder-xyz123' ); ?></label>
<textarea id="form-description" name="form[description]" rows="2" placeholder="<?php esc_attr_e( 'Brief description of this form', 'pc-form-builder-xyz123' ); ?>"><?php echo esc_textarea( $form->description ); ?></textarea>
</div>
<div class="pcfb-form-group">
<label for="form-status"><?php esc_html_e( 'Status', 'pc-form-builder-xyz123' ); ?></label>
<select id="form-status" name="form[status]">
<option value="active" <?php selected( $form->status, 'active' ); ?>><?php esc_html_e( 'Active', 'pc-form-builder-xyz123' ); ?></option>
<option value="inactive" <?php selected( $form->status, 'inactive' ); ?>><?php esc_html_e( 'Inactive', 'pc-form-builder-xyz123' ); ?></option>
</select>
</div>
</div>
</div>
<div class="pcfb-card pcfb-fields-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Form Fields', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-field-types-section">
<h3><?php esc_html_e( 'Add Fields to Your Form', 'pc-form-builder-xyz123' ); ?></h3>
<p class="description"><?php esc_html_e( 'Click on any field type below to add it to your form. You can then customize the label, placeholder, and other options.', 'pc-form-builder-xyz123' ); ?></p>
<div class="pcfb-field-type-buttons">
<?php foreach ( $field_types as $type => $label ) : ?>
<button type="button" class="pcfb-add-field-btn" data-field-type="<?php echo esc_attr( $type ); ?>">
<span class="dashicons <?php echo esc_attr( PCFB_Field_Icons::get_field_icon( $type ) ); ?>"></span>
<span class="pcfb-field-label"><?php echo esc_html( $label ); ?></span>
</button>
<?php endforeach; ?>
</div>
</div>
<div class="pcfb-form-fields">
<h3><?php esc_html_e( 'Form Structure', 'pc-form-builder-xyz123' ); ?></h3>
<p class="description"><?php esc_html_e( 'Drag and drop fields to reorder them. Click on a field to expand and edit its properties.', 'pc-form-builder-xyz123' ); ?></p>
<div id="pcfb-fields-container" class="pcfb-fields-container">
<?php if ( empty( $fields ) ) : ?>
<div class="pcfb-empty-fields">
<span class="dashicons dashicons-plus-alt2 pcfb-empty-icon"></span>
<p><?php esc_html_e( 'No fields added yet.', 'pc-form-builder-xyz123' ); ?></p>
<p class="description"><?php esc_html_e( 'Click a field type above to start building your form.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php else : ?>
<?php foreach ( $fields as $index => $field ) : ?>
<?php echo $helper->render_field_item( $field, $index ); ?>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
<div class="pcfb-card pcfb-sections-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Form Sections', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<p class="description"><?php esc_html_e( 'Organize your form fields into sections for better user experience.', 'pc-form-builder-xyz123' ); ?></p>
<div id="pcfb-sections-container" class="pcfb-sections-container">
<div class="pcfb-section-box pcfb-default-section">
<div class="pcfb-section-header">
<span class="dashicons dashicons-menu"></span>
<span class="pcfb-section-title"><?php esc_html_e( 'Default Section', 'pc-form-builder-xyz123' ); ?></span>
</div>
<div class="pcfb-section-content">
<p class="description"><?php esc_html_e( 'All fields are placed in this default section by default. You can add section breaks between fields.', 'pc-form-builder-xyz123' ); ?></p>
</div>
</div>
</div>
<button type="button" class="button pcfb-add-section-btn" id="pcfb-add-section">
<span class="dashicons dashicons-plus"></span>
<?php esc_html_e( 'Add Section', 'pc-form-builder-xyz123' ); ?>
</button>
</div>
</div>
</div>
<div class="pcfb-builder-sidebar">
<div class="pcfb-card pcfb-publish-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Publish', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<button type="submit" class="button button-primary button-large pcfb-save-btn">
<span class="dashicons dashicons-saved"></span>
<?php esc_html_e( 'Save Form', 'pc-form-builder-xyz123' ); ?>
</button>
<a href="<?php echo admin_url( 'admin.php?page=pcfb-all-forms' ); ?>" class="button button-large">
<?php esc_html_e( 'Cancel', 'pc-form-builder-xyz123' ); ?>
</a>
</div>
</div>
<div class="pcfb-card pcfb-settings-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Form Settings', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<div class="pcfb-form-group">
<label for="form-success-message"><?php esc_html_e( 'Success Message', 'pc-form-builder-xyz123' ); ?></label>
<textarea id="form-success-message" name="form[settings][success_message]" rows="3" placeholder="<?php esc_attr_e( 'Thank you! Your response has been submitted.', 'pc-form-builder-xyz123' ); ?>"><?php echo isset( $settings['success_message'] ) ? esc_textarea( $settings['success_message'] ) : ''; ?></textarea>
</div>
<div class="pcfb-form-group">
<label for="form-submit-text"><?php esc_html_e( 'Submit Button Text', 'pc-form-builder-xyz123' ); ?></label>
<input type="text" id="form-submit-text" name="form[settings][submit_text]" value="<?php echo isset( $settings['submit_text'] ) ? esc_attr( $settings['submit_text'] ) : __( 'Submit', 'pc-form-builder-xyz123' ); ?>">
</div>
</div>
</div>
<div class="pcfb-card pcfb-help-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Quick Tips', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<p><strong><?php esc_html_e( 'Available Field Types:', 'pc-form-builder-xyz123' ); ?></strong></p>
<ul>
<li><span class="dashicons dashicons-text"></span> <strong><?php esc_html_e( 'Text', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Single line text input', 'pc-form-builder-xyz123' ); ?></li>
<li><span class="dashicons dashicons-email"></span> <strong><?php esc_html_e( 'Email', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Email address with validation', 'pc-form-builder-xyz123' ); ?></li>
<li><span class="dashicons dashicons-admin-users"></span> <strong><?php esc_html_e( 'Name', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Full name field', 'pc-form-builder-xyz123' ); ?></li>
<li><span class="dashicons dashicons-editor-quote"></span> <strong><?php esc_html_e( 'Response', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Multi-line textarea for responses', 'pc-form-builder-xyz123' ); ?></li>
<li><span class="dashicons dashicons-arrow-down-alt2"></span> <strong><?php esc_html_e( 'Dropdown', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Select from predefined options', 'pc-form-builder-xyz123' ); ?></li>
<li><span class="dashicons dashicons-yes"></span> <strong><?php esc_html_e( 'Checkbox', 'pc-form-builder-xyz123' ); ?></strong> - <?php esc_html_e( 'Checkbox options', 'pc-form-builder-xyz123' ); ?></li>
</ul>
<hr>
<p><?php esc_html_e( 'After saving, use the shortcode to embed this form on any page or post.', 'pc-form-builder-xyz123' ); ?></p>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,111 @@
<div class="wrap pcfb-wrap">
<?php
$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
if ( empty( $form_id ) ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Form ID is required.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$form = PC_Form_Handler::get_form_by_id( $form_id );
if ( ! $form ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Form not found.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$paged = isset( $_GET['paged'] ) ? max( 1, intval( $_GET['paged'] ) ) : 1;
$per_page = 20;
$offset = ( $paged - 1 ) * $per_page;
$responses = PC_Form_Handler::get_form_responses( $form_id, array(
'limit' => $per_page,
'offset' => $offset,
) );
$total_responses = PC_Form_Handler::get_form_response_count( $form_id );
$total_pages = ceil( $total_responses / $per_page );
?>
<h1 class="wp-heading-inline">
<a href="<?php echo admin_url( 'admin.php?page=pcfb-responses' ); ?>" class="pcfb-back-link">
<span class="dashicons dashicons-arrow-left-alt2"></span>
</a>
<span class="pcfb-heading-icon dashicons dashicons-pressthis"></span>
<?php echo esc_html( $form->name ); ?> - <?php esc_html_e( 'Responses', 'pc-form-builder-xyz123' ); ?>
</h1>
<span class="title-ext">
<?php echo esc_html( $total_responses . ' ' . _n( 'Response', 'Responses', $total_responses, 'pc-form-builder-xyz123' ) ); ?>
</span>
<hr class="wp-header-end">
<div class="pcfb-form-responses-page">
<?php if ( empty( $responses ) ) : ?>
<div class="pcfb-empty-state">
<span class="dashicons dashicons-pressthis pcfb-empty-icon"></span>
<h3><?php esc_html_e( 'No responses yet', 'pc-form-builder-xyz123' ); ?></h3>
<p><?php esc_html_e( 'This form has not received any responses yet.', 'pc-form-builder-xyz123' ); ?></p>
</div>
<?php else : ?>
<div class="pcfb-responses-header">
<div class="pcfb-response-count-badge">
<span class="dashicons dashicons-pressthis"></span>
<?php echo esc_html( $total_responses . ' ' . _n( 'Response', 'Responses', $total_responses, 'pc-form-builder-xyz123' ) ); ?>
</div>
</div>
<table class="widefat pcfb-table pcfb-responses-table">
<thead>
<tr>
<th><?php esc_html_e( 'ID', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Submitted', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'IP Address', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Status', 'pc-form-builder-xyz123' ); ?></th>
<th><?php esc_html_e( 'Actions', 'pc-form-builder-xyz123' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $responses as $response ) : ?>
<?php
$detail_url = admin_url( 'admin.php?page=pcfb-responses&form_id=' . $form_id . '&response_id=' . $response->id );
$status_class = 'new' === $response->status ? 'status-new' : 'status-read';
$status_label = 'new' === $response->status ? __( 'New', 'pc-form-builder-xyz123' ) : __( 'Read', 'pc-form-builder-xyz123' );
?>
<tr>
<td><?php echo esc_html( $response->id ); ?></td>
<td><?php echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $response->created_at ) ) ); ?></td>
<td><?php echo esc_html( $response->user_ip ); ?></td>
<td>
<span class="pcfb-status <?php echo esc_attr( $status_class ); ?>">
<?php echo esc_html( $status_label ); ?>
</span>
</td>
<td>
<a href="<?php echo esc_url( $detail_url ); ?>" class="button button-small">
<?php esc_html_e( 'View Details', 'pc-form-builder-xyz123' ); ?>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if ( $total_pages > 1 ) : ?>
<div class="pcfb-pagination">
<?php
echo paginate_links( array(
'base' => admin_url( 'admin.php?page=pcfb-responses&form_id=' . $form_id . '&paged=%#%' ),
'format' => '',
'prev_text' => __( '&laquo; Previous', 'pc-form-builder-xyz123' ),
'next_text' => __( 'Next &raquo;', 'pc-form-builder-xyz123' ),
'total' => $total_pages,
'current' => $paged,
) );
?>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>

View File

@@ -0,0 +1,118 @@
<div class="wrap pcfb-wrap">
<?php
$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
$response_id = isset( $_GET['response_id'] ) ? intval( $_GET['response_id'] ) : 0;
if ( empty( $form_id ) || empty( $response_id ) ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Invalid request.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$form = PC_Form_Handler::get_form_by_id( $form_id );
if ( ! $form ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Form not found.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$response_data = PC_Form_Handler::get_response_data( $response_id );
if ( empty( $response_data ) ) {
echo '<div class="notice notice-error"><p>' . esc_html__( 'Response not found.', 'pc-form-builder-xyz123' ) . '</p></div>';
return;
}
$back_url = admin_url( 'admin.php?page=pcfb-responses&form_id=' . $form_id );
$response_meta = pcfb_get_response_meta( $response_id );
?>
<h1 class="wp-heading-inline">
<a href="<?php echo esc_url( $back_url ); ?>" class="pcfb-back-link">
<span class="dashicons dashicons-arrow-left-alt2"></span>
</a>
<span class="pcfb-heading-icon dashicons dashicons-pressthis"></span>
<?php esc_html_e( 'Response Details', 'pc-form-builder-xyz123' ); ?>
</h1>
<span class="title-ext">
<?php esc_html_e( 'Response #', 'pc-form-builder-xyz123' ); ?><?php echo esc_html( $response_id ); ?>
</span>
<hr class="wp-header-end">
<div class="pcfb-response-detail-page">
<div class="pcfb-response-meta">
<div class="pcfb-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Response Information', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<table class="widefat pcfb-meta-table">
<tr>
<th><?php esc_html_e( 'Form:', 'pc-form-builder-xyz123' ); ?></th>
<td><?php echo esc_html( $form->name ); ?></td>
</tr>
<tr>
<th><?php esc_html_e( 'Submitted:', 'pc-form-builder-xyz123' ); ?></th>
<td><?php echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $response_meta['created_at'] ) ) ); ?></td>
</tr>
<tr>
<th><?php esc_html_e( 'IP Address:', 'pc-form-builder-xyz123' ); ?></th>
<td><?php echo esc_html( $response_meta['user_ip'] ); ?></td>
</tr>
<tr>
<th><?php esc_html_e( 'User Agent:', 'pc-form-builder-xyz123' ); ?></th>
<td><?php echo esc_html( $response_meta['user_agent'] ); ?></td>
</tr>
</table>
</div>
</div>
</div>
<div class="pcfb-response-content">
<div class="pcfb-card">
<div class="pcfb-card-header">
<h2><?php esc_html_e( 'Submitted Data', 'pc-form-builder-xyz123' ); ?></h2>
</div>
<div class="pcfb-card-body">
<?php foreach ( $response_data as $data ) : ?>
<div class="pcfb-response-field">
<div class="pcfb-response-field-label">
<?php echo esc_html( $data->field_label ); ?>
</div>
<div class="pcfb-response-field-value">
<?php
if ( 'checkbox' === $data->field_type ) {
$options = maybe_unserialize( $data->field_value );
if ( is_array( $options ) ) {
echo esc_html( implode( ', ', $options ) );
} else {
echo esc_html( $data->field_value );
}
} elseif ( 'response' === $data->field_type ) {
echo wpautop( esc_html( $data->field_value ) );
} else {
echo esc_html( $data->field_value );
}
?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
</div>
<?php
function pcfb_get_response_meta( $response_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_responses';
$response = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE id = %d", $response_id ), ARRAY_A );
return $response ? $response : array(
'user_ip' => '',
'user_agent' => '',
'created_at' => '',
);
}
?>

View File

@@ -0,0 +1,74 @@
<div class="wrap pcfb-wrap">
<h1 class="wp-heading-inline">
<span class="pcfb-heading-icon dashicons dashicons-pressthis"></span>
<?php esc_html_e( 'Form Responses', 'pc-form-builder-xyz123' ); ?>
</h1>
<hr class="wp-header-end">
<?php
$forms = PC_Form_Handler::get_forms( array( 'limit' => 100 ) );
?>
<div class="pcfb-responses-page">
<?php if ( empty( $forms ) ) : ?>
<div class="pcfb-empty-state">
<span class="dashicons dashicons-pressthis pcfb-empty-icon"></span>
<h3><?php esc_html_e( 'No forms to show responses', 'pc-form-builder-xyz123' ); ?></h3>
<p><?php esc_html_e( 'Create a form first to start collecting and viewing responses.', 'pc-form-builder-xyz123' ); ?></p>
<a href="<?php echo admin_url( 'admin.php?page=pcfb-form-builder&form_id=new' ); ?>" class="button button-primary">
<?php esc_html_e( 'Create a Form', 'pc-form-builder-xyz123' ); ?>
</a>
</div>
<?php else : ?>
<div class="pcfb-responses-overview">
<h2><?php esc_html_e( 'Select a Form', 'pc-form-builder-xyz123' ); ?></h2>
<p class="description"><?php esc_html_e( 'Choose a form to view its responses.', 'pc-form-builder-xyz123' ); ?></p>
<div class="pcfb-forms-select-list">
<?php foreach ( $forms as $form ) : ?>
<?php
$response_count = PC_Form_Handler::get_form_response_count( $form->id );
$view_url = admin_url( 'admin.php?page=pcfb-responses&form_id=' . $form->id );
$status_class = 'active' === $form->status ? 'status-active' : 'status-inactive';
?>
<div class="pcfb-form-select-item">
<div class="pcfb-form-select-info">
<h3>
<a href="<?php echo esc_url( $view_url ); ?>">
<?php echo esc_html( $form->name ); ?>
</a>
</h3>
<span class="pcfb-status <?php echo esc_attr( $status_class ); ?>">
<?php echo esc_html( 'active' === $form->status ? __( 'Active', 'pc-form-builder-xyz123' ) : __( 'Inactive', 'pc-form-builder-xyz123' ) ); ?>
</span>
</div>
<div class="pcfb-form-select-stats">
<span class="pcfb-response-count">
<strong><?php echo esc_html( $response_count ); ?></strong>
<?php echo _n( 'Response', 'Responses', $response_count, 'pc-form-builder-xyz123' ); ?>
</span>
<a href="<?php echo esc_url( $view_url ); ?>" class="button button-small">
<?php esc_html_e( 'View Responses', 'pc-form-builder-xyz123' ); ?>
</a>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="pcfb-total-responses">
<?php
$total_responses = 0;
foreach ( $forms as $form ) {
$total_responses += PC_Form_Handler::get_form_response_count( $form->id );
}
?>
<div class="pcfb-total-card">
<span class="pcfb-total-number"><?php echo esc_html( $total_responses ); ?></span>
<span class="pcfb-total-label"><?php esc_html_e( 'Total Responses Across All Forms', 'pc-form-builder-xyz123' ); ?></span>
</div>
</div>
<?php endif; ?>
</div>
</div>

View File

@@ -0,0 +1,131 @@
<?php
/**
* Database Migration Class
*
* Handles creation and management of database tables for forms and responses.
*
* @package PCFormBuilder
*/
class PC_DB_Migration {
private static $charset_collate = '';
public static function activate() {
self::set_charset();
self::create_forms_table();
self::create_fields_table();
self::create_responses_table();
self::create_response_data_table();
update_option( 'pcfb_version', PCFB_VERSION );
}
public static function deactivate() {
// Cleanup if needed
}
private static function set_charset() {
global $wpdb;
self::$charset_collate = $wpdb->get_charset_collate();
}
private static function create_forms_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
$sql = "CREATE TABLE {$table_name} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
description text NOT NULL,
settings longtext NOT NULL,
status varchar(20) DEFAULT 'active' NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) " . self::$charset_collate . ";";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
private static function create_fields_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_fields';
$sql = "CREATE TABLE {$table_name} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
form_id mediumint(9) NOT NULL,
field_type varchar(50) NOT NULL,
field_label varchar(255) NOT NULL,
field_name varchar(255) NOT NULL,
placeholder varchar(255) DEFAULT '',
options longtext DEFAULT NULL,
validation_rules longtext DEFAULT NULL,
sort_order mediumint(9) DEFAULT 0 NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id),
KEY form_id (form_id)
) " . self::$charset_collate . ";";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
private static function create_responses_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_responses';
$sql = "CREATE TABLE {$table_name} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
form_id mediumint(9) NOT NULL,
user_ip varchar(100) DEFAULT '',
user_agent text DEFAULT '',
status varchar(20) DEFAULT 'new' NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id),
KEY form_id (form_id)
) " . self::$charset_collate . ";";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
private static function create_response_data_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_response_data';
$sql = "CREATE TABLE {$table_name} (
id mediumint(9) NOT NULL AUTO_INCREMENT,
response_id mediumint(9) NOT NULL,
field_id mediumint(9) NOT NULL,
field_value longtext NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id),
KEY response_id (response_id),
KEY field_id (field_id)
) " . self::$charset_collate . ";";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
public static function drop_tables() {
global $wpdb;
$tables = array(
$wpdb->prefix . 'pcfb_response_data',
$wpdb->prefix . 'pcfb_responses',
$wpdb->prefix . 'pcfb_fields',
$wpdb->prefix . 'pcfb_forms',
);
foreach ( $tables as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS {$table}" );
}
}
}

View File

@@ -0,0 +1,402 @@
<?php
/**
* Form Handler Class
*
* Handles form submission, validation, and storage.
*
* @package PCFormBuilder
*/
class PC_Form_Handler {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action( 'wp_ajax_pcfb_submit_form', array( $this, 'handle_form_submission' ) );
add_action( 'wp_ajax_nopriv_pcfb_submit_form', array( $this, 'handle_form_submission' ) );
add_action( 'wp_ajax_pcfb_add_field', array( $this, 'handle_add_field' ) );
add_shortcode( 'pcfb-form', array( $this, 'shortcode_form' ) );
}
public function handle_add_field() {
check_ajax_referer( 'pcfb_admin_nonce', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'pc-form-builder-xyz123' ) ) );
}
$field_type = isset( $_POST['field_type'] ) ? sanitize_text_field( $_POST['field_type'] ) : '';
$field_index = isset( $_POST['field_index'] ) ? intval( $_POST['field_index'] ) : 0;
if ( empty( $field_type ) ) {
wp_send_json_error( array( 'message' => __( 'Field type is required.', 'pc-form-builder-xyz123' ) ) );
}
require_once PCFB_PLUGIN_DIR . 'admin/class-admin-helper.php';
$helper = PCFB_Admin_Helper::get_instance();
ob_start();
$helper->render_new_field_item( $field_type, $field_index );
$html = ob_get_clean();
wp_send_json_success( array( 'html' => $html ) );
}
public function shortcode_form( $atts ) {
$atts = shortcode_atts( array(
'id' => 0,
), $atts );
if ( empty( $atts['id'] ) ) {
return '<p>' . esc_html__( 'Form ID is required.', 'pc-form-builder-xyz123' ) . '</p>';
}
$form = $this->get_form( intval( $atts['id'] ) );
if ( ! $form ) {
return '<p>' . esc_html__( 'Form not found.', 'pc-form-builder-xyz123' ) . '</p>';
}
if ( 'active' !== $form->status ) {
return '<p>' . esc_html__( 'This form is not currently active.', 'pc-form-builder-xyz123' ) . '</p>';
}
$fields = $this->get_form_fields( $form->id );
$settings = maybe_unserialize( $form->settings );
ob_start();
include PCFB_PLUGIN_DIR . 'public/templates/form-display.php';
return ob_get_clean();
}
private function get_form( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE id = %d", $form_id ) );
}
private function get_form_fields( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ) );
}
public function handle_form_submission() {
check_ajax_referer( 'pcfb_public_nonce', 'nonce' );
$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
$form_data = isset( $_POST['form_data'] ) ? $_POST['form_data'] : array();
if ( empty( $form_id ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid form ID.', 'pc-form-builder-xyz123' ) ) );
}
$form = $this->get_form( $form_id );
if ( ! $form ) {
wp_send_json_error( array( 'message' => __( 'Form not found.', 'pc-form-builder-xyz123' ) ) );
}
$fields = $this->get_form_fields( $form_id );
$errors = array();
$clean_data = array();
foreach ( $fields as $field ) {
$value = isset( $form_data[ $field->field_name ] ) ? trim( $form_data[ $field->field_name ] ) : '';
$validation_rules = maybe_unserialize( $field->validation_rules );
if ( ! empty( $validation_rules['required'] ) && empty( $value ) ) {
$errors[ $field->field_name ] = sprintf(
__( '%s is required.', 'pc-form-builder-xyz123' ),
$field->field_label
);
}
if ( ! empty( $value ) && 'email' === $field->field_type ) {
if ( ! is_email( $value ) ) {
$errors[ $field->field_name ] = __( 'Please enter a valid email address.', 'pc-form-builder-xyz123' );
}
}
$clean_data[ $field->id ] = sanitize_text_field( $value );
}
if ( ! empty( $errors ) ) {
wp_send_json_error( array( 'message' => __( 'Please fix the errors below.', 'pc-form-builder-xyz123' ), 'errors' => $errors ) );
}
$response_id = $this->save_response( $form_id, $clean_data );
if ( $response_id ) {
$success_message = ! empty( $settings['success_message'] )
? $settings['success_message']
: __( 'Thank you! Your response has been submitted.', 'pc-form-builder-xyz123' );
wp_send_json_success( array( 'message' => $success_message, 'response_id' => $response_id ) );
} else {
wp_send_json_error( array( 'message' => __( 'Failed to save your response. Please try again.', 'pc-form-builder-xyz123' ) ) );
}
}
private function save_response( $form_id, $field_data ) {
global $wpdb;
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$user_ip = $_SERVER['REMOTE_ADDR'] ?? '';
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$wpdb->insert(
$responses_table,
array(
'form_id' => $form_id,
'user_ip' => $user_ip,
'user_agent'=> $user_agent,
'status' => 'new',
)
);
if ( ! $wpdb->insert_id ) {
return false;
}
$response_id = $wpdb->insert_id;
foreach ( $field_data as $field_id => $value ) {
$wpdb->insert(
$response_data_table,
array(
'response_id' => $response_id,
'field_id' => $field_id,
'field_value' => $value,
)
);
}
return $response_id;
}
public static function get_forms( $args = array() ) {
global $wpdb;
$defaults = array(
'status' => 'active',
'orderby' => 'created_at',
'order' => 'DESC',
'limit' => -1,
);
$args = wp_parse_args( $args, $defaults );
$table_name = $wpdb->prefix . 'pcfb_forms';
$sql = "SELECT * FROM {$table_name}";
if ( ! empty( $args['status'] ) ) {
$sql .= $wpdb->prepare( " WHERE status = %s", $args['status'] );
}
$sql .= " ORDER BY {$args['orderby']} {$args['order']}";
if ( $args['limit'] > 0 ) {
$sql .= $wpdb->prepare( " LIMIT %d", $args['limit'] );
}
return $wpdb->get_results( $sql );
}
public static function get_form_by_id( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE id = %d", $form_id ) );
}
public static function get_form_count( $status = 'active' ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE status = %s", $status ) );
}
public static function get_form_response_count( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_responses';
return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE form_id = %d", $form_id ) );
}
public static function get_form_responses( $form_id, $args = array() ) {
global $wpdb;
$defaults = array(
'limit' => 20,
'offset' => 0,
'orderby' => 'created_at',
'order' => 'DESC',
);
$args = wp_parse_args( $args, $defaults );
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$sql = $wpdb->prepare(
"SELECT r.* FROM {$responses_table} r
WHERE r.form_id = %d
ORDER BY r.{$args['orderby']} {$args['order']}
LIMIT %d OFFSET %d",
$form_id,
$args['limit'],
$args['offset']
);
return $wpdb->get_results( $sql );
}
public static function get_response_data( $response_id ) {
global $wpdb;
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$fields_table = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_results(
$wpdb->prepare(
"SELECT rd.*, f.field_name, f.field_label, f.field_type
FROM {$response_data_table} rd
JOIN {$fields_table} f ON rd.field_id = f.id
WHERE rd.response_id = %d",
$response_id
)
);
}
public static function delete_form( $form_id ) {
global $wpdb;
$forms_table = $wpdb->prefix . 'pcfb_forms';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$response_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$responses_table} WHERE form_id = %d", $form_id ) );
if ( ! empty( $response_ids ) ) {
$response_ids_placeholder = implode( ',', array_map( 'intval', $response_ids ) );
$wpdb->query( "DELETE FROM {$response_data_table} WHERE response_id IN ({$response_ids_placeholder})" );
$wpdb->query( "DELETE FROM {$responses_table} WHERE form_id = {$form_id}" );
}
$wpdb->query( "DELETE FROM {$fields_table} WHERE form_id = {$form_id}" );
return $wpdb->delete( $forms_table, array( 'id' => $form_id ) );
}
public function save_form( $data, $fields = array() ) {
global $wpdb;
$forms_table = $wpdb->prefix . 'pcfb_forms';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$form_data = array(
'name' => sanitize_text_field( $data['name'] ),
'description' => sanitize_text_field( $data['description'] ),
'settings' => maybe_serialize( isset( $data['settings'] ) ? $data['settings'] : array() ),
'status' => isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'active',
);
if ( ! empty( $data['id'] ) ) {
$form_id = intval( $data['id'] );
$wpdb->update( $forms_table, $form_data, array( 'id' => $form_id ) );
$existing_fields = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$fields_table} WHERE form_id = %d", $form_id ) );
$existing_field_ids = ! empty( $existing_fields ) ? array_map( 'intval', $existing_fields ) : array();
$submitted_field_ids = array();
$sort_order = 0;
if ( ! empty( $fields ) && is_array( $fields ) ) {
foreach ( $fields as $field ) {
$field_data = array(
'form_id' => $form_id,
'field_type' => sanitize_text_field( $field['field_type'] ),
'field_label' => sanitize_text_field( $field['field_label'] ),
'field_name' => $this->generate_field_name( $field['field_label'], $form_id, isset( $field['id'] ) ? $field['id'] : 0 ),
'placeholder' => isset( $field['placeholder'] ) ? sanitize_text_field( $field['placeholder'] ) : '',
'options' => isset( $field['options'] ) ? maybe_serialize( $field['options'] ) : '',
'validation_rules' => isset( $field['validation_rules'] ) ? maybe_serialize( $field['validation_rules'] ) : '',
'sort_order' => $sort_order++,
);
if ( ! empty( $field['id'] ) ) {
$submitted_field_ids[] = intval( $field['id'] );
$wpdb->update( $fields_table, $field_data, array( 'id' => intval( $field['id'] ) ) );
} else {
$wpdb->insert( $fields_table, $field_data );
$submitted_field_ids[] = $wpdb->insert_id;
}
}
}
foreach ( $existing_field_ids as $field_id ) {
if ( ! in_array( $field_id, $submitted_field_ids ) ) {
$wpdb->delete( $fields_table, array( 'id' => $field_id ) );
}
}
return $form_id;
} else {
$wpdb->insert( $forms_table, $form_data );
$form_id = $wpdb->insert_id;
if ( $form_id && ! empty( $fields ) && is_array( $fields ) ) {
$sort_order = 0;
foreach ( $fields as $field ) {
$field_data = array(
'form_id' => $form_id,
'field_type' => sanitize_text_field( $field['field_type'] ),
'field_label' => sanitize_text_field( $field['field_label'] ),
'field_name' => $this->generate_field_name( $field['field_label'], $form_id ),
'placeholder' => isset( $field['placeholder'] ) ? sanitize_text_field( $field['placeholder'] ) : '',
'options' => isset( $field['options'] ) ? maybe_serialize( $field['options'] ) : '',
'validation_rules' => isset( $field['validation_rules'] ) ? maybe_serialize( $field['validation_rules'] ) : '',
'sort_order' => $sort_order++,
);
$wpdb->insert( $fields_table, $field_data );
}
}
return $form_id;
}
}
private function generate_field_name( $label, $form_id, $existing_id = 0 ) {
$base_name = sanitize_title( $label );
$base_name = preg_replace( '/[^a-z0-9_]/', '', strtolower( $base_name ) );
if ( empty( $base_name ) ) {
$base_name = 'field_' . time();
}
global $wpdb;
$fields_table = $wpdb->prefix . 'pcfb_fields';
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$fields_table} WHERE form_id = %d AND field_name LIKE %s",
$form_id,
$base_name . '%'
);
$count = $wpdb->get_var( $query );
if ( $count > 0 ) {
return $base_name . '_' . ( $count + 1 );
}
return $base_name;
}
}

View File

@@ -0,0 +1,10 @@
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"external_directory": {
"*": "deny",
"*/fir-qa0i/*": "allow",
"apps/c7f9e5c6-e7c2-4258-a583-ccffcf9791c8/fir-qa0i/*": "allow"
}
}
}

View File

@@ -0,0 +1,128 @@
<?php
/**
* Plugin Name: Plugin Compass Form Builder
* Plugin URI: https://plugincompass.com/plugins/pc-form-builder-xyz123
* Update URI: false
* Description: A complete form builder plugin with form builder, all forms management, and responses tracking.
* Version: 1.0.0
* Author: Plugin Compass
* Author URI: https://plugincompass.com
* Text Domain: pc-form-builder-xyz123
* Domain Path: /languages
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*
* @package PCFormBuilder
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'PCFB_VERSION', '1.0.0' );
define( 'PCFB_PLUGIN_FILE', __FILE__ );
define( 'PCFB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
define( 'PCFB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'PCFB_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
require_once PCFB_PLUGIN_DIR . 'includes/class-db-migration.php';
require_once PCFB_PLUGIN_DIR . 'includes/class-form-handler.php';
require_once PCFB_PLUGIN_DIR . 'admin/admin-menu.php';
class PC_Form_Builder {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action( 'init', array( $this, 'init' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_public_assets' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
}
public function init() {
load_plugin_textdomain( 'pc-form-builder-xyz123', false, dirname( PCFB_PLUGIN_BASENAME ) . '/languages' );
PC_Form_Handler::get_instance();
PCFB_Admin_Menu::get_instance();
}
public function enqueue_public_assets() {
wp_enqueue_style(
'pcfb-public-style',
PCFB_PLUGIN_URL . 'public/css/public-style.css',
array(),
PCFB_VERSION
);
wp_enqueue_script(
'pcfb-public-script',
PCFB_PLUGIN_URL . 'public/js/public-script.js',
array( 'jquery' ),
PCFB_VERSION,
true
);
wp_localize_script( 'pcfb-public-script', 'pcfbVars', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'pcfb_public_nonce' ),
) );
}
public function enqueue_admin_assets() {
$screen = get_current_screen();
if ( 'toplevel_page_pcfb-form-builder' === $screen->id ||
'form-builder_page_pcfb-all-forms' === $screen->id ||
'form-builder_page_pcfb-responses' === $screen->id ) {
wp_enqueue_style(
'pcfb-admin-style',
PCFB_PLUGIN_URL . 'admin/css/admin-style.css',
array(),
PCFB_VERSION
);
wp_enqueue_script(
'pcfb-admin-script',
PCFB_PLUGIN_URL . 'admin/js/admin-script.js',
array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-draggable' ),
PCFB_VERSION,
true
);
wp_localize_script( 'pcfb-admin-script', 'pcfbAdminVars', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'pcfb_admin_nonce' ),
'i18n' => array(
'confirmDelete' => __( 'Are you sure you want to delete this form?', 'pc-form-builder-xyz123' ),
'confirmDeleteField' => __( 'Are you sure you want to delete this field?', 'pc-form-builder-xyz123' ),
'fieldLabel' => __( 'Field Label', 'pc-form-builder-xyz123' ),
'fieldPlaceholder' => __( 'Placeholder text', 'pc-form-builder-xyz123' ),
'required' => __( 'Required', 'pc-form-builder-xyz123' ),
'delete' => __( 'Delete', 'pc-form-builder-xyz123' ),
),
) );
}
}
}
register_activation_hook( __FILE__, array( 'PC_DB_Migration', 'activate' ) );
register_deactivation_hook( __FILE__, array( 'PC_DB_Migration', 'deactivate' ) );
register_uninstall_hook( __FILE__, array( 'PC_Form_Builder', 'uninstall' ) );
add_action( 'plugins_loaded', array( 'PC_Form_Builder', 'get_instance' ) );
add_filter( 'site_transient_update_plugins', function( $value ) {
$plugin_file = plugin_basename( __FILE__ );
if ( isset( $value->response[ $plugin_file ] ) ) {
unset( $value->response[ $plugin_file ] );
}
return $value;
} );

View File

@@ -0,0 +1,528 @@
/**
* PC Form Builder Public Styles
*
* Frontend styling for the form builder plugin.
*
* @package PCFormBuilder
*/
/* CSS Variables */
:root {
--pcfb-primary: #2271b1;
--pcfb-primary-dark: #135e96;
--pcfb-primary-light: #72aee6;
--pcfb-success: #00a32a;
--pcfb-success-light: #dcfce1;
--pcfb-danger: #d63638;
--pcfb-danger-light: #fbe9e9;
--pcfb-warning: #dba617;
--pcfb-warning-light: #fff9c4;
--pcfb-text: #3c434a;
--pcfb-text-light: #6c7781;
--pcfb-bg: #ffffff;
--pcfb-bg-light: #f6f7f7;
--pcfb-border: #e1e2e3;
--pcfb-border-radius: 6px;
--pcfb-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--pcfb-transition: all 0.2s ease;
--pcfb-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
/* Reset & Base */
.pcfb-form-wrapper {
font-family: var(--pcfb-font-family);
font-size: 16px;
line-height: 1.5;
color: var(--pcfb-text);
box-sizing: border-box;
}
.pcfb-form-wrapper *,
.pcfb-form-wrapper *::before,
.pcfb-form-wrapper *::after {
box-sizing: border-box;
}
/* Container */
.pcfb-form-container {
background: var(--pcfb-bg);
border: 1px solid var(--pcfb-border);
border-radius: var(--pcfb-border-radius);
box-shadow: var(--pcfb-box-shadow);
padding: 30px;
max-width: 100%;
}
/* Form Header */
.pcfb-form-header {
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 1px solid var(--pcfb-border);
}
.pcfb-form-title {
margin: 0 0 10px;
font-size: 24px;
font-weight: 700;
color: var(--pcfb-text);
line-height: 1.3;
}
.pcfb-form-description {
margin: 0;
font-size: 15px;
color: var(--pcfb-text-light);
}
/* Form Fields */
.pcfb-form-fields {
display: flex;
flex-direction: column;
gap: 20px;
}
.pcfb-form-group {
display: flex;
flex-direction: column;
}
.pcfb-label {
font-weight: 600;
font-size: 14px;
color: var(--pcfb-text);
margin-bottom: 8px;
}
.pcfb-required {
color: var(--pcfb-danger);
margin-left: 3px;
}
/* Input Styles */
.pcfb-input,
.pcfb-textarea,
.pcfb-select {
width: 100%;
padding: 12px 15px;
font-family: inherit;
font-size: 15px;
line-height: 1.5;
color: var(--pcfb-text);
background-color: var(--pcfb-bg);
border: 1px solid var(--pcfb-border);
border-radius: var(--pcfb-border-radius);
transition: var(--pcfb-transition);
appearance: none;
}
.pcfb-input:focus,
.pcfb-textarea:focus,
.pcfb-select:focus {
outline: none;
border-color: var(--pcfb-primary);
box-shadow: 0 0 0 3px rgba(34, 113, 177, 0.15);
}
.pcfb-input::placeholder,
.pcfb-textarea::placeholder {
color: var(--pcfb-text-light);
opacity: 1;
}
.pcfb-textarea {
resize: vertical;
min-height: 100px;
max-height: 400px;
}
.pcfb-select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236c7781' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 15px center;
padding-right: 40px;
cursor: pointer;
}
/* Checkbox Styles */
.pcfb-checkbox-group {
display: flex;
flex-direction: column;
gap: 10px;
}
.pcfb-checkbox-label {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
font-weight: 400;
font-size: 15px;
color: var(--pcfb-text);
padding: 5px 0;
}
.pcfb-checkbox-label:hover .pcfb-checkbox-text {
color: var(--pcfb-primary);
}
.pcfb-checkbox {
width: 18px;
height: 18px;
margin: 0;
cursor: pointer;
accent-color: var(--pcfb-primary);
flex-shrink: 0;
}
.pcfb-checkbox:checked + .pcfb-checkbox-text {
color: var(--pcfb-text);
}
.pcfb-checkbox-text {
transition: var(--pcfb-transition);
}
/* Form Footer */
.pcfb-form-footer {
margin-top: 30px;
padding-top: 25px;
border-top: 1px solid var(--pcfb-border);
}
/* Submit Button */
.pcfb-submit-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 14px 30px;
font-family: inherit;
font-size: 16px;
font-weight: 600;
line-height: 1;
color: #fff;
background: var(--pcfb-primary);
border: none;
border-radius: var(--pcfb-border-radius);
cursor: pointer;
transition: var(--pcfb-transition);
text-decoration: none;
min-width: 160px;
}
.pcfb-submit-button:hover {
background: var(--pcfb-primary-dark);
transform: translateY(-1px);
}
.pcfb-submit-button:active {
transform: translateY(0);
}
.pcfb-submit-button:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
/* Spinner */
.pcfb-spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: #fff;
border-radius: 50%;
animation: pcfb-spin 0.8s linear infinite;
}
@keyframes pcfb-spin {
to {
transform: rotate(360deg);
}
}
/* Error Messages */
.pcfb-field-error {
display: none;
margin-top: 6px;
font-size: 13px;
color: var(--pcfb-danger);
}
.pcfb-form-group.error .pcfb-input,
.pcfb-form-group.error .pcfb-textarea,
.pcfb-form-group.error .pcfb-select {
border-color: var(--pcfb-danger);
background-color: var(--pcfb-danger-light);
}
.pcfb-form-group.error .pcfb-field-error {
display: block;
}
/* Success/Error Messages */
.pcfb-form-message {
margin-top: 20px;
padding: 15px 20px;
border-radius: var(--pcfb-border-radius);
animation: pcfb-fadeIn 0.3s ease;
}
@keyframes pcfb-fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.pcfb-success-message {
background-color: var(--pcfb-success-light);
border: 1px solid var(--pcfb-success);
}
.pcfb-error-message {
background-color: var(--pcfb-danger-light);
border: 1px solid var(--pcfb-danger);
}
.pcfb-message-content {
display: flex;
align-items: flex-start;
gap: 12px;
}
.pcfb-message-icon {
font-size: 24px;
width: 24px;
height: 24px;
flex-shrink: 0;
}
.pcfb-success-message .pcfb-message-icon {
color: var(--pcfb-success);
}
.pcfb-error-message .pcfb-message-icon {
color: var(--pcfb-danger);
}
.pcfb-message-text {
margin: 0;
font-size: 15px;
color: var(--pcfb-text);
}
/* No Fields Message */
.pcfb-no-fields {
text-align: center;
color: var(--pcfb-text-light);
padding: 40px 20px;
background: var(--pcfb-bg-light);
border-radius: var(--pcfb-border-radius);
margin: 0;
}
/* Responsive Design */
@media screen and (max-width: 600px) {
.pcfb-form-container {
padding: 20px;
}
.pcfb-form-title {
font-size: 20px;
}
.pcfb-form-fields {
gap: 15px;
}
.pcfb-input,
.pcfb-textarea,
.pcfb-select {
padding: 10px 12px;
font-size: 16px;
}
.pcfb-submit-button {
width: 100%;
padding: 14px 20px;
}
.pcfb-checkbox-label {
font-size: 14px;
}
}
/* Dark Mode Support */
@media (prefers-color-scheme: dark) {
.pcfb-form-wrapper {
--pcfb-text: #f0f0f1;
--pcfb-text-light: #a0a5aa;
--pcfb-bg: #1d2327;
--pcfb-bg-light: #2c3338;
--pcfb-border: #3c434a;
--pcfb-border-radius: 6px;
--pcfb-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.pcfb-form-container {
background: var(--pcfb-bg);
border-color: var(--pcfb-border);
}
.pcfb-form-header {
border-bottom-color: var(--pcfb-border);
}
.pcfb-form-title {
color: var(--pcfb-text);
}
.pcfb-form-description {
color: var(--pcfb-text-light);
}
.pcfb-label {
color: var(--pcfb-text);
}
.pcfb-input,
.pcfb-textarea,
.pcfb-select {
background-color: var(--pcfb-bg-light);
border-color: var(--pcfb-border);
color: var(--pcfb-text);
}
.pcfb-input::placeholder,
.pcfb-textarea::placeholder {
color: var(--pcfb-text-light);
}
.pcfb-checkbox-label {
color: var(--pcfb-text);
}
.pcfb-form-footer {
border-top-color: var(--pcfb-border);
}
.pcfb-message-text {
color: var(--pcfb-text);
}
.pcfb-no-fields {
background: var(--pcfb-bg-light);
color: var(--pcfb-text-light);
}
}
/* High Contrast Mode */
@media (prefers-contrast: high) {
.pcfb-form-container {
border-width: 2px;
}
.pcfb-input,
.pcfb-textarea,
.pcfb-select {
border-width: 2px;
}
.pcfb-submit-button {
border: 2px solid #fff;
}
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.pcfb-form-wrapper *,
.pcfb-form-wrapper *::before,
.pcfb-form-wrapper *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Print Styles */
@media print {
.pcfb-form-wrapper {
box-shadow: none;
border: 1px solid #000;
}
.pcfb-form-container {
box-shadow: none;
}
.pcfb-submit-button {
display: none;
}
}
/* Accessibility Focus Styles */
.pcfb-input:focus-visible,
.pcfb-textarea:focus-visible,
.pcfb-select:focus-visible,
.pcfb-checkbox:focus-visible {
outline: 2px solid var(--pcfb-primary);
outline-offset: 2px;
}
/* Validation Styles */
.pcfb-input:invalid:not(:placeholder-shown),
.pcfb-input.pattern-violation:not(:placeholder-shown) {
border-color: var(--pcfb-danger);
}
/* Loading State */
.pcfb-form.loading .pcfb-submit-text {
display: none;
}
.pcfb-form.loading .pcfb-submit-loader {
display: inline-flex !important;
align-items: center;
gap: 8px;
}
.pcfb-form.loading .pcfb-submit-button {
cursor: wait;
}
/* Form Layout Variations */
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-form-group {
flex-direction: row;
align-items: flex-start;
gap: 20px;
}
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-label {
flex: 0 0 150px;
padding-top: 12px;
margin-bottom: 0;
}
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-input,
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-textarea,
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-select {
flex: 1;
}
@media screen and (max-width: 768px) {
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-form-group {
flex-direction: column;
gap: 8px;
}
.pcfb-form-wrapper.pcfb-form-aligned .pcfb-label {
flex: none;
padding-top: 0;
}
}

View File

@@ -0,0 +1,136 @@
/**
* PC Form Builder Public Scripts
*
* Frontend JavaScript functionality for form handling.
*
* @package PCFormBuilder
*/
(function($) {
'use strict';
var PCFB_Public = {
init: function() {
this.initForms();
},
initForms: function() {
var self = this;
$(document).on('submit', '.pcfb-form', function(e) {
e.preventDefault();
self.handleFormSubmit($(this));
});
},
handleFormSubmit: function($form) {
var self = this;
var formId = $form.data('form-id');
var $submitButton = $form.find('.pcfb-submit-button');
var $submitText = $form.find('.pcfb-submit-text');
var $submitLoader = $form.find('.pcfb-submit-loader');
var $successMessage = $form.closest('.pcfb-form-container').find('.pcfb-success-message');
var $errorMessage = $form.closest('.pcfb-form-container').find('.pcfb-error-message');
$form.find('.pcfb-form-group').removeClass('error');
$form.find('.pcfb-field-error').text('');
$errorMessage.hide().find('.pcfb-message-text').text('');
$successMessage.hide();
var formData = $form.serialize();
var ajaxData = {
action: 'pcfb_submit_form',
form_id: formId,
form_data: {},
nonce: pcfbVars.nonce
};
$form.find('input, textarea, select').each(function() {
var $field = $(this);
var name = $field.attr('name');
if (name && name !== 'action' && name !== 'form_id' && name !== 'pcfb_nonce') {
if ($field.is(':checkbox')) {
if ($field.is(':checked')) {
if (!ajaxData.form_data[name]) {
ajaxData.form_data[name] = [];
}
ajaxData.form_data[name].push($field.val());
}
} else if ($field.is(':radio')) {
if ($field.is(':checked')) {
ajaxData.form_data[name] = $field.val();
}
} else {
ajaxData.form_data[name] = $field.val();
}
}
});
$form.addClass('loading');
$submitButton.prop('disabled', true);
$submitText.hide();
$submitLoader.show();
$.ajax({
url: pcfbVars.ajaxurl,
type: 'POST',
data: ajaxData,
dataType: 'json',
success: function(response) {
$form.removeClass('loading');
$submitButton.prop('disabled', false);
$submitText.show();
$submitLoader.hide();
if (response.success) {
$successMessage.find('.pcfb-message-text').text(response.data.message || 'Thank you!');
$successMessage.show();
$form.hide();
if (response.data.response_id) {
console.log('Response ID:', response.data.response_id);
}
} else {
if (response.data.errors) {
$.each(response.data.errors, function(fieldName, errorMessage) {
var $fieldGroup = $form.find('[name="' + fieldName + '"]').closest('.pcfb-form-group');
if ($fieldGroup.length === 0) {
$fieldGroup = $form.find('[name^="' + fieldName + '"]').closest('.pcfb-form-group');
}
if ($fieldGroup.length > 0) {
$fieldGroup.addClass('error');
$fieldGroup.find('.pcfb-field-error').text(errorMessage);
}
});
}
var errorText = response.data.message || 'An error occurred. Please try again.';
$errorMessage.find('.pcfb-message-text').text(errorText);
$errorMessage.show();
}
},
error: function(xhr, status, error) {
$form.removeClass('loading');
$submitButton.prop('disabled', false);
$submitText.show();
$submitLoader.hide();
var errorText = 'An error occurred. Please try again.';
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
errorText = xhr.responseJSON.data.message;
} else if (xhr.statusText) {
errorText = xhr.statusText;
}
$errorMessage.find('.pcfb-message-text').text(errorText);
$errorMessage.show();
}
});
}
};
$(document).ready(function() {
PCFB_Public.init();
});
})(jQuery);

View File

@@ -0,0 +1,166 @@
<?php
/**
* Form Display Template
*
* Frontend template for displaying forms.
*
* @package PCFormBuilder
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$form_id = ! empty( $form->id ) ? $form->id : 0;
$form_name = ! empty( $form->name ) ? $form->name : '';
$form_description = ! empty( $form->description ) ? $form->description : '';
$submit_text = ! empty( $settings['submit_text'] ) ? $settings['submit_text'] : __( 'Submit', 'pc-form-builder-xyz123' );
$success_message = ! empty( $settings['success_message'] ) ? $settings['success_message'] : __( 'Thank you! Your response has been submitted.', 'pc-form-builder-xyz123' );
?>
<div class="pcfb-form-wrapper" id="pcfb-form-wrapper-<?php echo esc_attr( $form_id ); ?>">
<div class="pcfb-form-container">
<?php if ( ! empty( $form_name ) ) : ?>
<div class="pcfb-form-header">
<h2 class="pcfb-form-title"><?php echo esc_html( $form_name ); ?></h2>
<?php if ( ! empty( $form_description ) ) : ?>
<p class="pcfb-form-description"><?php echo esc_html( $form_description ); ?></p>
<?php endif; ?>
</div>
<?php endif; ?>
<form class="pcfb-form" id="pcfb-form-<?php echo esc_attr( $form_id ); ?>" data-form-id="<?php echo esc_attr( $form_id ); ?>">
<?php wp_nonce_field( 'pcfb_public_nonce', 'pcfb_nonce' ); ?>
<input type="hidden" name="action" value="pcfb_submit_form">
<input type="hidden" name="form_id" value="<?php echo esc_attr( $form_id ); ?>">
<div class="pcfb-form-fields">
<?php if ( ! empty( $fields ) && is_array( $fields ) ) : ?>
<?php foreach ( $fields as $field ) : ?>
<?php
$field_id = ! empty( $field->id ) ? $field->id : 0;
$field_name = ! empty( $field->field_name ) ? $field->field_name : '';
$field_label = ! empty( $field->field_label ) ? $field->field_label : '';
$field_type = ! empty( $field->field_type ) ? $field->field_type : 'text';
$placeholder = ! empty( $field->placeholder ) ? $field->placeholder : '';
$options = ! empty( $field->options ) ? maybe_unserialize( $field->options ) : array();
$validation_rules = ! empty( $field->validation_rules ) ? maybe_unserialize( $field->validation_rules ) : array();
$is_required = ! empty( $validation_rules['required'] );
?>
<div class="pcfb-form-group pcfb-field-<?php echo esc_attr( $field_type ); ?>">
<label class="pcfb-label" for="<?php echo esc_attr( 'pcfb-' . $form_id . '-' . $field_name ); ?>">
<?php echo esc_html( $field_label ); ?>
<?php if ( $is_required ) : ?>
<span class="pcfb-required">*</span>
<?php endif; ?>
</label>
<?php switch ( $field_type ) :
case 'text':
case 'email':
case 'name':
?>
<input
type="<?php echo esc_attr( 'email' === $field_type ? 'email' : 'text' ); ?>"
id="<?php echo esc_attr( 'pcfb-' . $form_id . '-' . $field_name ); ?>"
name="<?php echo esc_attr( $field_name ); ?>"
class="pcfb-input"
placeholder="<?php echo esc_attr( $placeholder ); ?>"
<?php if ( $is_required ) : ?>required<?php endif; ?>
>
<?php
break;
case 'response':
?>
<textarea
id="<?php echo esc_attr( 'pcfb-' . $form_id . '-' . $field_name ); ?>"
name="<?php echo esc_attr( $field_name ); ?>"
class="pcfb-textarea"
rows="5"
placeholder="<?php echo esc_attr( $placeholder ); ?>"
<?php if ( $is_required ) : ?>required<?php endif; ?>
></textarea>
<?php
break;
case 'dropdown':
?>
<select
id="<?php echo esc_attr( 'pcfb-' . $form_id . '-' . $field_name ); ?>"
name="<?php echo esc_attr( $field_name ); ?>"
class="pcfb-select"
<?php if ( $is_required ) : ?>required<?php endif; ?>
>
<option value=""><?php echo esc_html( $placeholder ? $placeholder : __( '-- Select --', 'pc-form-builder-xyz123' ) ); ?></option>
<?php if ( ! empty( $options ) && is_array( $options ) ) : ?>
<?php foreach ( $options as $option ) : ?>
<?php if ( ! empty( trim( $option ) ) ) : ?>
<option value="<?php echo esc_attr( trim( $option ) ); ?>"><?php echo esc_html( trim( $option ) ); ?></option>
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
</select>
<?php
break;
case 'checkbox':
if ( ! empty( $options ) && is_array( $options ) ) :
?>
<div class="pcfb-checkbox-group">
<?php foreach ( $options as $index => $option ) : ?>
<?php if ( ! empty( trim( $option ) ) ) : ?>
<?php $checkbox_id = 'pcfb-' . $form_id . '-' . $field_name . '-' . $index; ?>
<label class="pcfb-checkbox-label" for="<?php echo esc_attr( $checkbox_id ); ?>">
<input
type="checkbox"
id="<?php echo esc_attr( $checkbox_id ); ?>"
name="<?php echo esc_attr( $field_name ); ?>[]"
value="<?php echo esc_attr( trim( $option ) ); ?>"
class="pcfb-checkbox"
>
<span class="pcfb-checkbox-text"><?php echo esc_html( trim( $option ) ); ?></span>
</label>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php
break;
endswitch; ?>
<span class="pcfb-field-error" id="<?php echo esc_attr( 'pcfb-error-' . $form_id . '-' . $field_name ); ?>"></span>
</div>
<?php endforeach; ?>
<?php else : ?>
<p class="pcfb-no-fields"><?php esc_html_e( 'This form has no fields yet.', 'pc-form-builder-xyz123' ); ?></p>
<?php endif; ?>
</div>
<div class="pcfb-form-footer">
<button type="submit" class="pcfb-submit-button">
<span class="pcfb-submit-text"><?php echo esc_html( $submit_text ); ?></span>
<span class="pcfb-submit-loader" style="display: none;">
<span class="pcfb-spinner"></span>
<?php esc_html_e( 'Submitting...', 'pc-form-builder-xyz123' ); ?>
</span>
</button>
</div>
</form>
<div class="pcfb-form-message pcfb-success-message" style="display: none;">
<div class="pcfb-message-content">
<span class="pcfb-message-icon dashicons dashicons-yes-alt"></span>
<p class="pcfb-message-text"><?php echo esc_html( $success_message ); ?></p>
</div>
</div>
<div class="pcfb-form-message pcfb-error-message" style="display: none;">
<div class="pcfb-message-content">
<span class="pcfb-message-icon dashicons dashicons-warning"></span>
<p class="pcfb-message-text"></p>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,50 @@
#!/bin/bash
#
# PC Form Builder Plugin Validation Script
#
# Lints all PHP files and verifies plugin header.
#
set -e
PLUGIN_DIR="$1"
if [ -z "$PLUGIN_DIR" ]; then
echo "Usage: ./scripts/validate-wordpress-plugin.sh <plugin-root-directory>"
exit 1
fi
if [ ! -d "$PLUGIN_DIR" ]; then
echo "Error: Directory $PLUGIN_DIR does not exist"
exit 1
fi
echo "Validating WordPress Plugin: $PLUGIN_DIR"
echo "=========================================="
ERRORS=0
for php_file in $(find "$PLUGIN_DIR" -name "*.php" -type f); do
echo "Checking: $php_file"
output=$(php -l "$php_file" 2>&1)
if echo "$output" | grep -q "No syntax errors detected"; then
echo " ✓ Syntax OK"
else
echo " ✗ Syntax Error:"
echo "$output"
ERRORS=$((ERRORS + 1))
fi
done
echo ""
echo "=========================================="
if [ $ERRORS -gt 0 ]; then
echo "Found $ERRORS error(s)"
exit 1
else
echo "All PHP files passed syntax validation!"
exit 0
fi

View File

@@ -0,0 +1,36 @@
<?php
/**
* PC Form Builder Uninstall
*
* Cleans up plugin data when uninstalled.
*
* @package PCFormBuilder
*/
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! current_user_can( 'delete_plugins' ) ) {
exit;
}
delete_option( 'pcfb_version' );
delete_option( 'pcfb_activated' );
global $wpdb;
$tables = array(
$wpdb->prefix . 'pcfb_forms',
$wpdb->prefix . 'pcfb_fields',
$wpdb->prefix . 'pcfb_responses',
$wpdb->prefix . 'pcfb_response_data',
);
foreach ( $tables as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS {$table}" );
}