bitcx_aipb_setup_actions();
// Filter for adding "Settings" link on Plugin Activate Page
add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'bitcx_aipb_add_settings_link'));
// Filter for adding "Contact Support" link to plugin details
add_filter('plugin_row_meta', array($this, 'bitcx_aipb_add_support_link'), 10, 2);
}
/**
* Callback function for the "Settings" link filter
*/
public function bitcx_aipb_add_settings_link($links) {
$settings_link = 'Settings';
array_push($links, $settings_link);
return $links;
}
/**
* Callback function for the "Contact Support" link filter
*/
public function bitcx_aipb_add_support_link($data, $file) {
if (plugin_basename(__FILE__) === $file) {
// Check if 'Description' key exists, initialize if not
if (!isset($data['Description'])) {
$data['Description'] = '';
}
$support_link = 'Contact Support';
$data['Description'] .= $support_link;
}
return $data;
}
/**
* Setting up Hooks
*/
public function bitcx_aipb_setup_actions() {
// ChatGPT API Key Conformation
add_action("admin_init", array($this , 'bitcx_aipb_handle_api_submit'));
// Create Custom Menu
add_action('admin_menu', array($this, 'bitcx_aipb_create_menu'));
// Custom Post types
add_action('init', array($this, 'bitcx_aipb_insert_portfolio_cpt'));
add_action('init', array($this, 'bitcx_aipb_insert_testimonial_cpt'));
add_action('init', array($this, 'bitcx_aipb_insert_cta_cpt'));
// Shortcode for front (user) page
add_shortcode('bitcx_aipb_form', array($this, 'bitcx_aipb_pr_shortcode'));
$this->bitcx_aipb_init_metabox();
// Admin side page css
add_action( 'admin_head', array($this,'bitcx_aipb_custom_admin_css') );
//Create page on Activation
add_action('init', array($this, 'bitcx_aipb_create_pr_page'));
//Deactivation Hook
register_deactivation_hook(__FILE__, array($this, 'bitcx_aipb_deactivate_plugin'));
//API Ajax Handler
add_action('wp_ajax_bitcx_aipb_get_nonce', array($this, 'bitcx_aipb_ai_request'));
add_action('wp_ajax_nopriv_bitcx_aipb_get_nonce', array($this, 'bitcx_aipb_ai_request'));
add_action('wp_ajax_bitcx_aipb_ai_response', array($this, 'bitcx_aipb_ai_request'));
add_action('wp_ajax_nopriv_bitcx_aipb_ai_response', array($this, 'bitcx_aipb_ai_request'));
// Fix custom taxonomy parent menu
add_action( 'parent_file', array($this, 'bitcx_highlight_taxonomy_parent_menu'));
}
/**
* Enqueue CSS for admin side Dashboard Page
*/
public function bitcx_aipb_custom_admin_css(){
wp_enqueue_style("bitcx_aipb_admin_css", plugin_dir_url(__FILE__) . "src/admin/css/admin.css", array(), $this->plugin_version);
}
/**
* Create Main Menu and Sub menues for Proposal Builder Plugin
*/
public function bitcx_aipb_create_menu() {
add_menu_page(
'Proposal Builder', // Page title
'Proposal Builder', // Menu title
'manage_options', // Capability
'bitcx_aipb_proposal_builder', // Menu slug
false, // Callback function to display content
'dashicons-portfolio', // Icon
30 // Position in the menu
);
add_submenu_page(
'bitcx_aipb_proposal_builder', // Parent menu slug
'Proposal Builder', // Page title
'Proposal Builder', // Menu title
'manage_options', // Capability
'bitcx_aipb_settings', // Menu slug
array($this, 'bitcx_aipb_settings_page'), // Callback function to display content
0
);
add_submenu_page(
'bitcx_aipb_proposal_builder', // Parent menu slug
'Portfolio Categories', // Page title
'Portfolio Categories', // Menu title
'manage_options', // Capability
'edit-tags.php?taxonomy=bitcx_portfolio_category', // Menu slug
null // Callback function
);
}
/**
* @param mixed
*
* Setting Parent of Portfolio Category
*
* @return mixed
*/
public function bitcx_highlight_taxonomy_parent_menu( $parent_file ) {
if ( get_current_screen()->taxonomy == 'bitcx_portfolio_category' ) {
$parent_file = 'bitcx_aipb_proposal_builder';
}
return $parent_file;
}
/**
* Returns admin Proposal Builder Main page template
*/
public function bitcx_aipb_settings_page() {
require_once 'src/admin/templates/bitcx_aipb_admin_template.php';
}
/**
* Admin side API key submit handler
*/
public function bitcx_aipb_handle_api_submit() {
// Handle form submission
if (isset($_POST['bitcx_aipb_ai_save_api_key']) && isset($_POST['nonce_api_key'])) {
if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce_api_key'])), 'bitcx_aipb_nonce_api_key_submit')) {
$_SESSION["bitcx_aipb_api_message_error"] = "Nonce verification failed. Please try again.";
return;
}
// Sanitize and save API key
$bitcx_aipb_api_key = sanitize_text_field($_POST['bitcx_aipb_ai_api_key']);
$bitcx_aipb_is_valid = $this->bitcx_aipb_verify_api_key($bitcx_aipb_api_key);
// Instantiate the class
if ($bitcx_aipb_is_valid) {
update_option('bitcx_aipb_ai_api_key', sanitize_text_field($bitcx_aipb_api_key));
$_SESSION["bitcx_aipb_api_message_success"] = "API key is valid!";
} else {
$_SESSION["bitcx_aipb_api_message_error"] = "Invalid API key. Please try again.";
}
}
}
/**
* @param string
*
* Verify API Key
*
* @return boolean
*/
public function bitcx_aipb_verify_api_key($bitcx_aipb_api_key) {
$bitcx_aipb_api_url = 'https://api.openai.com/v1/models';
$bitcx_aipb_api_key = sanitize_text_field($bitcx_aipb_api_key);
// Set the headers
$headers = [
'Authorization' => 'Bearer ' . $bitcx_aipb_api_key,
];
// Set HTTP request arguments
$args = [
'headers' => $headers,
];
// Make the API request using WordPress HTTP API
$response = wp_remote_get($bitcx_aipb_api_url, $args);
// Check for errors
if (is_wp_error($response)) {
return false;
}
$body = wp_remote_retrieve_body($response);
$response_data = json_decode($body);
return !(isset($response_data) && !empty($response_data->error));
}
/**
* bitcx api request from form
*
* @return json
*/
public function bitcx_aipb_ai_request() {
// Get the action from the AJAX request
$action = sanitize_text_field( $_POST['action'] ?? '' );
// If the action is 'get_nonce', generate and return a nonce
if ($action === 'bitcx_aipb_get_nonce') {
// Generate nonce
$nonce = wp_create_nonce('bitcx_aipb_openai_nonce');
if (!wp_verify_nonce($nonce, 'bitcx_aipb_openai_nonce')) {
wp_send_json_error('Invalid nonce');
}
// Return the nonce to the client
echo wp_json_encode(['nonce' => $nonce]);
exit; // Exit to prevent further execution of OpenAI request
}
// If the action is not 'get_nonce', proceed with OpenAI request
// Get the API key from a secure location
$api_key = esc_attr(get_option('bitcx_aipb_ai_api_key'));
// Get the input prompt from the AJAX request
$prompt = sanitize_text_field($_POST['prompt'] ?? '');
// Verify nonce
$nonce = sanitize_key($_POST['nonce'] ?? '');
if (!wp_verify_nonce($nonce, 'bitcx_aipb_openai_nonce')) {
die('Invalid nonce');
}
// Set the request arguments
// Set the request arguments with a timeout of 20 seconds
$args = array(
'body' => wp_json_encode(array(
'model' => 'gpt-3.5-turbo',
'messages' => array(
array('role' => 'user', 'content' => $prompt),
),
)),
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
),
'timeout' => 30, // Set timeout to 20 seconds (or adjust as needed)
);
// Make the request using wp_remote_post
$response = wp_remote_post('https://api.openai.com/v1/chat/completions', $args);
// Check for errors
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
echo wp_json_encode(['error' => $error_message]);
} else {
// Retrieve the response body
$body = wp_remote_retrieve_body($response);
// Send the OpenAI response back to the client
echo wp_json_encode(['response' => $body]);
}
}
/**
* Create Page: Proposal Form
*/
public function bitcx_aipb_create_pr_page() {
// Check if the page creation process has already been completed
if (get_transient('bitcx_aipb_page_created')) {
return;
}
$check_page_exist = get_page_by_path(sanitize_title("Proposal Page"), OBJECT, 'page');
// Check if the page already exists
if (empty($check_page_exist)) {
$page_id = wp_insert_post(
array(
'comment_status' => 'close',
'ping_status' => 'close',
'post_author' => 1,
'post_title' => ucwords('Proposal Page'),
'post_name' => strtolower(str_replace(' ', '-', trim('Proposal Page'))),
'post_status' => 'publish',
'post_content' => '[bitcx_aipb_form]',
'post_type' => 'page',
)
);
if ($page_id) {
update_option('bitcx_aipb_page_id', sanitize_text_field($page_id));
}
}
// Set a transient to indicate that the page creation process has been completed
set_transient('bitcx_aipb_page_created', true);
}
/**
* Meta box initialization.
*/
public function bitcx_aipb_init_metabox() {
add_action('add_meta_boxes', array($this, 'bitcx_aipb_add_meta_box'));
add_action('save_post', array($this, 'bitcx_aipb_save_post'), 10, 2);
}
/**
* @param array
*
* Adds the meta box container.
*
* @return void
*/
public function bitcx_aipb_add_meta_box($post_type) {
// Limit meta box to certain post types.
$post_types = array('bitcx_portfolio');
if (in_array($post_type, $post_types)) {
add_meta_box(
'bitcx_portfolio_fields',
__('Portfolio Fields', 'textdomain'),
array($this, 'bitcx_aipb_render_meta_box_content'),
$post_type,
'advanced',
'high'
);
}
}
/**
* @param int
*
* Save the meta when the post is saved.
*/
public function bitcx_aipb_save_post($post_id) {
/*
* We need to verify this came from our screen and with proper authorization,
* because save_post can be triggered at other times.
*/
// Check if our nonce is set.
if (!isset($_POST['bitcx_aipb_inner_custom_box_nonce'])) {
return $post_id;
}
$nonce = isset($_POST['bitcx_aipb_inner_custom_box_nonce']) ? sanitize_text_field($_POST['bitcx_aipb_inner_custom_box_nonce']) : '';
// Verify that the nonce is valid.
if (!wp_verify_nonce($nonce, 'bitcx_aipb_inner_custom_box')) {
return $post_id;
}
/*
* If this is an autosave, our form has not been submitted,
* so we don't want to do anything.
*/
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $post_id;
}
// Check the user's permissions.
if ('page' == $_POST['post_type']) {
if (!current_user_can('edit_page', $post_id)) {
return $post_id;
}
} else {
if (!current_user_can('edit_post', $post_id)) {
return $post_id;
}
}
/* OK, it's safe for us to save the data now. */
// Sanitize the user input.
$mydata = sanitize_text_field($_POST['bitcx_portfolio_link']);
// Update the meta field.
update_post_meta($post_id, 'bitcx_portfolio_item_link', $mydata);
}
/**
* @param mixed
*
* Render Meta Box content.
*/
public function bitcx_aipb_render_meta_box_content($post) {
// Add a nonce field so we can check for it later.
wp_nonce_field('bitcx_aipb_inner_custom_box', 'bitcx_aipb_inner_custom_box_nonce');
// Use get_post_meta to retrieve an existing value from the database.
$value = get_post_meta($post->ID, 'bitcx_portfolio_item_link', true);
// Display the form, using the current value.
?>
__('Portfolios', 'ai-proposal-builder'),
'singular_name' => _x('Portfolio', 'singular', 'ai-proposal-builder'),
'menu_name' => _x('Portfolios', 'admin menu', 'ai-proposal-builder'),
'name_admin_bar' => _x('Portfolio', 'admin bar', 'ai-proposal-builder'),
'add_new' => _x('Add New', 'add new', 'ai-proposal-builder'),
'add_new_item' => __('Add New Portfolio', 'ai-proposal-builder'),
'new_item' => __('New Portfolio', 'ai-proposal-builder'),
'edit_item' => __('Edit Portfolio', 'ai-proposal-builder'),
'view_item' => __('View Portfolio', 'ai-proposal-builder'),
'all_items' => __('All Portfolios', 'ai-proposal-builder'),
'search_items' => __('Search Portfolios', 'ai-proposal-builder'),
'not_found' => __('No Portfolios found.', 'ai-proposal-builder'),
);
$args = array(
'supports' => $supports,
'labels' => $labels,
'public' => true,
'query_var' => true,
'rewrite' => array('slug' => 'bitcx_portfolio'),
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 20, // Adjusted menu position
'show_in_menu' => 'bitcx_aipb_proposal_builder',
);
register_post_type('bitcx_portfolio', $args);
$category_labels = array(
'name' => _x('Portfolio Categories', 'taxonomy general name', 'ai-proposal-builder'),
'singular_name' => _x('Portfolio Category', 'taxonomy singular name', 'ai-proposal-builder'),
'search_items' => __('Search Portfolio Categories', 'ai-proposal-builder'),
'all_items' => __('All Portfolio Categories', 'ai-proposal-builder'),
'parent_item' => __('Parent Portfolio Category', 'ai-proposal-builder'),
'parent_item_colon' => __('Parent Portfolio Category:', 'ai-proposal-builder'),
'edit_item' => __('Edit Portfolio Category', 'ai-proposal-builder'),
'update_item' => __('Update Portfolio Category', 'ai-proposal-builder'),
'add_new_item' => __('Add New Portfolio Category', 'ai-proposal-builder'),
'new_item_name' => __('New Portfolio Category Name', 'ai-proposal-builder'),
'menu_name' => __('Portfolio Categories', 'ai-proposal-builder'),
);
register_taxonomy('bitcx_portfolio_category', 'bitcx_portfolio', array(
'hierarchical' => true,
'labels' => $category_labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array('slug' => 'bitcx_portfolio_category', 'with_front' => false),
));
register_taxonomy_for_object_type('bitcx_portfolio_category', 'bitcx_portfolio');
}
/**
* Testimonial CPT
*/
public function bitcx_aipb_insert_testimonial_cpt() {
$supports = array(
'title', // post title
'editor', // post content
'author', // post author
'thumbnail', // featured images
'excerpt', // post excerpt
'custom-fields', // custom fields
'revisions', // post revisions
);
$labels = array(
'name' => _x('Testimonials', 'plural', 'ai-proposal-builder'),
'singular_name' => _x('Testimonials', 'singular', 'ai-proposal-builder'),
'menu_name' => _x('Testimonials', 'admin menu', 'ai-proposal-builder'),
'name_admin_bar' => _x('Testimonials', 'admin bar', 'ai-proposal-builder'),
'add_new' => _x('Add New', 'add new', 'ai-proposal-builder'),
'add_new_item' => __('Add New Testimonial', 'ai-proposal-builder'),
'new_item' => __('New Testimonial', 'ai-proposal-builder'),
'edit_item' => __('Edit Testimonial', 'ai-proposal-builder'),
'view_item' => __('View Testimonial', 'ai-proposal-builder'),
'all_items' => __('Testimonials', 'ai-proposal-builder'),
'search_items' => __('Search Testimonials', 'ai-proposal-builder'),
'not_found' => __('No Testimonial found.', 'ai-proposal-builder'),
);
$args = array(
'supports' => $supports,
'labels' => $labels,
'public' => true,
'query_var' => true,
'rewrite' => array('slug' => 'bitcx_testimonial'),
'has_archive' => true,
'hierarchical' => false,
'show_in_menu' => 'bitcx_aipb_proposal_builder',
);
register_post_type('bitcx_testimonial', $args);
}
/**
* CTAs CPT
*/
public function bitcx_aipb_insert_cta_cpt() {
$supports = array(
'title', // post title
'editor', // post content
'author', // post author
'thumbnail', // featured images
'excerpt', // post excerpt
'custom-fields', // custom fields
'revisions', // post revisions
);
$labels = array(
'name' => _x('CTAs', 'plural', 'ai-proposal-builder'),
'singular_name' => _x('CTA', 'singular', 'ai-proposal-builder'),
'menu_name' => _x('CTAs', 'admin menu', 'ai-proposal-builder'),
'name_admin_bar' => _x('CTAs', 'admin bar', 'ai-proposal-builder'),
'add_new' => _x('Add New', 'add new', 'ai-proposal-builder'),
'add_new_item' => __('Add New CTA', 'ai-proposal-builder'),
'new_item' => __('New CTA', 'ai-proposal-builder'),
'edit_item' => __('Edit CTA', 'ai-proposal-builder'),
'view_item' => __('View CTA', 'ai-proposal-builder'),
'all_items' => __('CTAs', 'ai-proposal-builder'),
'search_items' => __('Search CTAs', 'ai-proposal-builder'),
'not_found' => __('No CTA found.', 'ai-proposal-builder'),
);
$args = array(
'supports' => $supports,
'labels' => $labels,
'public' => true,
'query_var' => true,
'rewrite' => array('slug' => 'bitcx_aipb_cta'),
'has_archive' => true,
'hierarchical' => false,
'show_in_menu' => 'bitcx_aipb_proposal_builder',
);
register_post_type('bitcx_aipb_cta', $args);
}
/**
* Enqueue Files
*/
public function bitcx_aipb_enqueue_files() {
wp_enqueue_style("bitcx_aipb_builder_css", plugin_dir_url(__FILE__) . "dist/6decdfa8.css", array(), $this->plugin_version);
/*
Swiper.js:
- Repository: [Swiper.js GitHub Repository](https://github.com/nolimits4web/swiper/)
- Uncompressed Source Code: [Swiper.js Uncompressed Source](https://github.com/nolimits4web/swiper/tree/master/src)
- Documentation: [Swiper.js Documentation](https://swiperjs.com/get-started)
*/
wp_enqueue_script("bitcx-aipb-swiper", plugin_dir_url(__FILE__) . "src/public/js/swiper-bundle.min.js", array('jquery'), $this->plugin_version, true);
/*
jsPDF:
- Repository: [jsPDF GitHub Repository](https://github.com/parallax/jsPDF/)
- Uncompressed Source Code: [jsPDF Uncompressed Source](https://github.com/parallax/jsPDF/tree/master/src)
- Documentation: [jsPDF Documentation](https://raw.githack.com/MrRio/jsPDF/master/docs/index.html)
*/
wp_enqueue_script("bitcx-aipb-pdf", plugin_dir_url(__FILE__) . "src/public/js/jspdf.min.js", array('jquery'), $this->plugin_version, true);
wp_enqueue_script("bitcx_aipb_builder_js", plugin_dir_url(__FILE__) . "dist/f3834259.js", array('jquery'), $this->plugin_version, true);
wp_localize_script( 'bitcx_aipb_user', 'bitcx_aipb_ajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));
wp_enqueue_script( 'jquery');
}
/**
* Get Portfolio Categories
*/
public function bitcx_aipb_get_portfolio_cats() {
$args = array(
'taxonomy' => 'bitcx_portfolio_category',
'orderby' => 'name',
'order' => 'ASC'
);
$portfolio_cats = get_categories($args);
return $portfolio_cats;
}
/**
* Get Portfolio Items
*/
public function bitcx_aipb_get_portfolio() {
$args = array(
'post_type' => 'bitcx_portfolio',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$portfolio = new WP_Query($args);
return $portfolio;
}
/**
* Get Testimonials Items
*/
public function bitcx_aipb_get_testimonials() {
$args = array(
'post_type' => 'bitcx_testimonial',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$testimonials = new WP_Query($args);
return $testimonials;
}
/**
* Get CTAs Items
*/
public function bitcx_aipb_get_ctas() {
$args = array(
'post_type' => 'bitcx_aipb_cta',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$ctas = new WP_Query($args);
return $ctas;
}
/**
* Shortcode callback
*/
public function bitcx_aipb_pr_shortcode() {
$this->bitcx_aipb_enqueue_files();
ob_start();
$portfolio_items = $this->bitcx_aipb_get_portfolio();
$portfolio_cats = $this->bitcx_aipb_get_portfolio_cats();
$testimonial_items = $this->bitcx_aipb_get_testimonials();
$cta_items = $this->bitcx_aipb_get_ctas();
require_once 'src/public/templates/bitcx_aipb_shortcode_template.php';
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* Deactivate Plugin
*/
public function bitcx_aipb_deactivate_plugin(){
set_transient('bitcx_aipb_page_created', false);
delete_option( 'bitcx_aipb_ai_api_key' );
}
}
// instantiate the plugin class
$wp_plugin_init = new bitcx_AI_Proposal_Builder();