shell bypass 403
<?php
namespace FluentFormPro\Components\Post;
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly.
}
use FluentForm\App\Api\FormProperties;
use FluentForm\App\Modules\Form\FormFieldsParser;
use FluentForm\App\Services\ConditionAssesor;
use FluentForm\App\Services\FormBuilder\ShortCodeParser;
use FluentForm\Framework\Helpers\ArrayHelper;
use FluentFormPro\Components\Post\Components\HierarchicalTaxonomy;
use FluentFormPro\Components\Post\Components\NonHierarchicalTaxonomy;
use FluentFormPro\Components\PostSelectionField;
class PostFormHandler
{
use Getter;
public function renderTaxonomyFields($data, $form)
{
if ($form->type != 'post') return;
if (isset($data['taxonomy_settings'])) {
if ($data['taxonomy_settings']['hierarchical']) {
return (new HierarchicalTaxonomy)->compile($data, $form);
} else {
return (new NonHierarchicalTaxonomy)->compile($data, $form);
}
}
}
public function maybeRenderPostSelectionField($form)
{
if ($form->type != 'post') return;
$feeds = $this->getFormFeeds($form);
if (!$feeds) {
return;
}
foreach ($feeds as $feed) {
$feed->value = json_decode($feed->value, true);
if (ArrayHelper::get($feed->value, 'post_form_type') == 'update') {
$postType = $this->getPostType($form);
do_action_deprecated(
'fluentformpro_populate_post_form_values',
[
$form,
$feed->value,
$postType
],
FLUENTFORM_FRAMEWORK_UPGRADE,
'fluentform/populate_post_form_values',
'Use fluentform/populate_post_form_values instead of fluentformpro_populate_post_form_values.'
);
do_action('fluentform/populate_post_form_values', $form, $feed->value, $postType);
return;
}
}
}
public function onFormSubmissionInserted($entryId, $formData, $form)
{
$feeds = $this->getFormFeeds($form);
if (!$feeds) {
return;
}
$postType = $this->getPostType($form);
$entry = wpFluent()->table('fluentform_submissions')
->where('id', $entryId)
->first();
foreach ($feeds as $feed) {
$feed->value = json_decode($feed->value, true);
if (!ArrayHelper::get($feed->value, 'feed_status')) continue;
if (isset($feed->value['acf_mappings'])) {
$feed->value['acf_mappings'] = AcfHelper::resolveDateFieldFormat($feed->value['acf_mappings'], $form);
}
if (isset($feed->value['jetengine_mappings'])) {
$feed->value['jetengine_mappings'] = JetEngineHelper::resolveDateFieldFormat($feed->value['jetengine_mappings'], $form);
}
if (isset($feed->value['meta_fields_mapping'])) {
$feed->value['meta_fields_mapping'] = static::resolveCustomMetaFileTypeField($feed->value['meta_fields_mapping'], $form, $formData);
}
$feed = ShortCodeParser::parse($feed->value, $entryId, $formData, $form);
if (!$this->isConditionMet($feed, $formData)) {
continue;
}
$this->createPostFromFeed($feed, $entry, $formData, $form, $postType);
}
}
public function createPostFromFeed($feed, $entry, $formData, $form, $postType = false)
{
if (!is_object($entry)) {
$entry = wpFluent()->table('fluentform_submissions')
->where('id', $entry)
->first();
}
if (!$postType) {
$postType = $this->getPostType($form);
}
$postData = [
'post_type' => $postType,
'post_status' => ArrayHelper::get($feed, 'post_status'),
'comment_status' => ArrayHelper::get($feed, 'comment_status'),
'post_category' => array(ArrayHelper::get($feed, 'default_category'))
];
if (!empty($entry->user_id)) {
$postData['post_author'] = $entry->user_id;
}
$postData = $this->mapPostFields($feed, $postData);
$isUpdatePost = 'update' == ArrayHelper::get($feed, 'post_form_type');
$postId = null;
if ($isUpdatePost && $postField = FormFieldsParser::getElement($form, 'post_update', ['raw'])) {
$postFieldName = ArrayHelper::get(array_pop($postField), 'raw.attributes.name', '');
$postId = ArrayHelper::get($formData, $postFieldName);
}
$postData = $this->mapMetaFields($feed, $postData, $postType, $formData, $postId);
$formInputs = FormFieldsParser::getInputs($form, ['element', 'raw', 'attributes']);
foreach ($formInputs as $field) {
if ($field['element'] == 'featured_image') {
$fieldName = $field['attributes']['name'];
if (!empty($formData[$fieldName][0])) {
$postData['featured_Image'] = $formData[$fieldName][0];
} elseif (
ArrayHelper::isTrue($formData, 'remove_featured_image') &&
$isUpdatePost &&
$postId
) {
if (delete_post_thumbnail($postId) && $attachmentId = get_post_thumbnail_id($postId)) {
wp_delete_attachment($attachmentId);
};
}
}
if (isset($field['raw']['taxonomy_settings'])) {
$postData = $this->mapTaxonomyFields(
$field['raw']['taxonomy_settings'], $postData, $formData
);
}
}
if ($isUpdatePost && $postId) {
$postData['ID'] = $postId;
}
$this->insertPost($feed, $postData, $form, $entry->id);
}
protected function isConditionMet($feed, $formData)
{
// We have to check if the feed meets the conditional Logic
$conditionSettings = ArrayHelper::get($feed, 'conditionals');
if (
!$conditionSettings ||
!ArrayHelper::isTrue($conditionSettings, 'status') ||
!count(ArrayHelper::get($conditionSettings, 'conditions'))
) {
return true;
}
return ConditionAssesor::evaluate($feed, $formData);
}
public function getFormFeeds($form)
{
return wpFluent()->table('fluentform_form_meta')
->where('form_id', $form->id)
->where('meta_key', 'postFeeds')
->get();
}
public function getPostType($form)
{
$postSettings = wpFluent()->table('fluentform_form_meta')
->where('form_id', $form->id)
->where('meta_key', 'post_settings')
->first()->value;
$postSettings = json_decode($postSettings);
return $postSettings->post_type;
}
protected function mapPostFields($feed, $postData)
{
foreach ($feed['post_fields_mapping'] as $postFieldMapping) {
$postField = $postFieldMapping['post_field'];
if ($postField != 'post_title') {
$postData[$postField] = $postFieldMapping['form_field'];
} else {
$postData[$postField] = wp_strip_all_tags($postFieldMapping['form_field']);
}
}
return $postData;
}
protected function mapMetaFields($feed, $postData, $postType, $formData = [], $postId = null)
{
$metaInputs = ArrayHelper::get($feed, 'meta_fields_mapping', []);
$isUpdate = ('update' == ArrayHelper::get($feed, 'post_form_type'));
foreach ($metaInputs as $metaFieldMapping) {
if (!isset($metaFieldMapping['meta_value'])) {
continue;
}
$isFile = (false !== strpos($metaFieldMapping['meta_value'], 'uploads/fluentform'));
//store old attachment's id when update file meta
$existingAttachmentIds = [];
if ($isFile && $isUpdate && $postId) {
$existingValue = get_post_custom_values($metaFieldMapping['meta_key'], $postId);
if ($existingValue && ($existingValue) > 0) {
$existingAttachmentIds = explode(',', $existingValue[0]);
}
}
if ($isFile) {
//make attachment's
$files = explode(', ', $metaFieldMapping['meta_value']);
$attachmentIds = [];
foreach ($files as $file) {
if ($attachmentId = $this->getAttachmentToImageUrl($file)) {
$attachmentIds[] = $attachmentId;
}
}
// merge old and new attachment's
if ($existingAttachmentIds) {
$attachmentIds = array_filter(array_merge($attachmentIds, $existingAttachmentIds));
}
$metaFieldMapping['meta_value'] = join(',', $attachmentIds);
}
$metaKey = $metaFieldMapping['meta_key'];
$postData['meta_input'][$metaKey] = $metaFieldMapping['meta_value'];
}
if (AcfHelper::hasAcf()) {
$postData['acf_mappings'] = [];
if ($acfFields = ArrayHelper::get($feed, 'acf_mappings', [])) {
$metaValues = AcfHelper::prepareGeneralFieldsData($acfFields, $postType, $isUpdate);
if ($metaValues) {
$postData['acf_mappings'] = array_merge($postData['acf_mappings'], $metaValues);
}
}
if ($advancedAcfFields = ArrayHelper::get($feed, 'advanced_acf_mappings', [])) {
$metaValues = AcfHelper::prepareAdvancedFieldsData($advancedAcfFields, $formData, $postType, $isUpdate);
if ($metaValues) {
$postData['acf_mappings'] = array_merge($postData['acf_mappings'], $metaValues);
}
}
}
if (JetEngineHelper::hasJetEngine() && $metaValues = JetEngineHelper::prepareMetaValues($feed, $postType, $formData, $isUpdate)) {
$postData['meta_input'] = array_merge(ArrayHelper::get($postData, 'meta_input', []), $metaValues);
}
if (MetaboxHelper::hasMetabox()) {
$metaboxFields = [
'general' => ArrayHelper::get($feed, 'metabox_mappings', []),
'advanced' => ArrayHelper::get($feed, 'advanced_metabox_mappings', [])
];
$metaBoxValues = MetaboxHelper::prepareFieldsData($metaboxFields, $postType, $formData, $isUpdate);
if ($metaBoxValues) {
$postData['metabox_mappings'] = $metaBoxValues;
}
}
return $postData;
}
protected function mapTaxonomyFields($taxonomySettings, $postData, $formData)
{
$taxonomyFieldName = $taxonomySettings['name'];
if (!isset($formData[$taxonomyFieldName])) {
return $postData;
}
$taxonomyData = $formData[$taxonomyFieldName];
if ($taxonomyFieldName == 'category') {
if ($taxonomyData) {
$postData['post_category'] = (array)$taxonomyData;
}
} else if ($taxonomyFieldName == 'post_tag') {
$tags = explode(',', $taxonomyData);
$postData['tags_input'] = array_map('trim', $tags);
} else {
$postData['tax_input'][$taxonomyFieldName] = $taxonomyData;
}
return $postData;
}
protected function insertPost($feed, $postData, $form, $entryId)
{
$acfFields = [];
if (isset($postData['acf_mappings'])) {
$acfFields = $postData['acf_mappings'];
unset($postData['acf_mappings']);
}
$metaBoxFields = [];
if(isset($postData['metabox_mappings'])) {
$metaBoxFields = $postData['metabox_mappings'];
unset($postData['metabox_mappings']);
}
$taxInput = null;
if (isset($postData['tax_input'])) {
$taxInput = $postData['tax_input'];
unset($postData['tax_input']);
}
$updatingPost = false;
$allowedGuest = !!ArrayHelper::get($feed, 'allowed_guest_user', true);
if (isset($feed['post_form_type']) && $feed['post_form_type'] == 'update') {
if (empty($postData['ID'])) {
$this->logAction($form->id, $entryId, "Update Skipped because of Empty Post ID",
'Post Updated Skipped', 'failed');
return;
}
if (!$allowedGuest && empty($postData['post_author'])) {
$this->logAction($form->id, $entryId, "Update not allowed from Guest User",
'Post Updated Skipped', 'info');
return;
}
if (!$allowedGuest && !$userCanUpdate = $this->ifUserCanUpdate($form, $postData)) {
$this->logAction($form->id, $entryId, "Update skipped because current user isn't Author of this post.",
'Post Updated Skipped', 'failed');
return;
}
$updatingPost = true;
$postId = wp_update_post($postData, true);
//@todo popuplate custom fields and taxonomies
} else {
if (!$allowedGuest && empty($postData['post_author'])) {
$this->logAction($form->id, $entryId, "Create not allowed from Guest User",
'Post Created Skipped', 'info');
return;
}
$postId = wp_insert_post($postData);
}
if (is_wp_error($postId)) {
$this->logAction($form->id, $entryId, $postId->get_error_message(), 'Post Integration Failed', 'failed');
return;
}
// Since WP doesn't allow setting terms for logged-out user,
// we'll handle it manually by saving the terms by looping.
if ($taxInput) {
foreach ($taxInput as $taxonomy => $tags) {
wp_set_post_terms($postId, $tags, $taxonomy);
}
}
if ($acfFields && function_exists('update_field')) {
foreach ($acfFields as $fieldKey => $value) {
update_field($fieldKey, $value, $postId);
}
if (function_exists('acf_save_post_revision') && !apply_filters('fluentform/disable_acf_post_meta_revision', false)) {
acf_save_post_revision($postId);
}
}
if($metaBoxFields && function_exists('rwmb_set_meta')) {
foreach ($metaBoxFields as $fieldKey => $value) {
rwmb_set_meta($postId, $fieldKey, $value);
}
}
$editLink = get_edit_post_link($postId);
if (!$editLink) {
$editLink = admin_url('post.php?post=' . $postId . '&action=edit');
}
$type = $updatingPost ?' Updated' : ' Created ';
$info = 'WP Post/CPT'.$type.' from submission. Post ID: ' . $postId . '. <a href="' . $editLink . '" target="_blank">Edit Post/CPT</a>';
$this->logAction($form->id, $entryId, $info ,"Post $type from form submission", 'success' );
wpFluent()->table('fluentform_submission_meta')
->insert([
'response_id' => $entryId,
'form_id' => $form->id,
'meta_key' => '__postFeeds_created_id',
'value' => $postId,
'name' => 'Post/CPT Created',
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql'),
]);
update_post_meta($postId, '_fluentform_id', $form->id);
if (!function_exists('set_post_thumbnail')) {
require_once(ABSPATH . 'wp-admin/includes/image.php');
}
if (!empty($feed['post_format'])) {
$format = 'post-format-' . $feed['post_format'];
wp_set_post_terms($postId, $format, 'post_format');
}
if (isset($postData['featured_Image'])) {
$this->setFeaturedImage($postId, $postData['featured_Image']);
}
do_action_deprecated(
'fluentform_post_integration_success',
[
$postId,
$postData,
$entryId,
$form,
$feed
],
FLUENTFORM_FRAMEWORK_UPGRADE,
'fluentform/post_integration_success',
'Use fluentform/post_integration_success instead of fluentform_post_integration_success.'
);
do_action('fluentform/post_integration_success', $postId, $postData, $entryId, $form, $feed);
}
protected function setFeaturedImage($postId, $featuredImage)
{
$attach_id = $this->getAttachmentToImageUrl($featuredImage);
if ($attach_id) {
// And finally assign featured image to post
return set_post_thumbnail($postId, $attach_id);
}
return false;
}
public function getAttachmentToImageUrl($fileUrl, $postId = 0)
{
//for media upload check if already uploaded as media
$attachmentId = attachment_url_to_postid($fileUrl);
if ($attachmentId) {
return $attachmentId;
}
$path = wp_upload_dir()['basedir'] . FLUENTFORM_UPLOAD_DIR;
$file = $path . substr($fileUrl, strrpos($fileUrl, '/'));
$upload_dir = wp_upload_dir();
$fileArray = explode('-ff-', $file);
$actualName = array_pop($fileArray);
$unique_file_name = wp_unique_filename($upload_dir['path'], $actualName); // Generate unique name
$destination = $upload_dir['path'] . '/' . $unique_file_name;
$newFileUrl = $upload_dir['url'] . '/' . $unique_file_name;
$result = copy($file, $destination);
$filePath = $file;
if ($result) {
$filePath = $destination;
}
// Check image file type
$wp_filetype = wp_check_filetype($unique_file_name, null);
// Set attachment data
$attachment = array(
'post_mime_type' => $wp_filetype['type'],
'post_title' => sanitize_file_name($unique_file_name),
'post_content' => '',
'post_status' => 'inherit',
'guid' => $newFileUrl
);
// Create the attachment
$attach_id = wp_insert_attachment($attachment, $filePath, $postId);
if (!function_exists('wp_generate_attachment_metadata')) {
// Include image.php
require_once(ABSPATH . 'wp-admin/includes/image.php');
}
// Define attachment metadata
$attach_data = wp_generate_attachment_metadata($attach_id, $filePath);
// Assign metadata to attachment
wp_update_attachment_metadata($attach_id, $attach_data);
return $attach_id;
}
/**
* Log Integration result
*
* @param $formId
* @param $entryId
* @param string $info
* @param string $title
* @param string $status
*
* @return void
*/
protected function logAction($formId, $entryId, $info, $title, $status)
{
$logData = [
'parent_source_id' => $formId,
'source_type' => 'submission_item',
'source_id' => $entryId,
'component' => 'postFeeds',
'status' => $status,
'title' => $title,
'description' => $info
];
do_action('fluentform/log_data', $logData);
}
private function ifUserCanUpdate($form, $postData)
{
$status = true;
$formInputs = (new FormProperties($form))->inputs(['raw']);
if ($postUpdateField = ArrayHelper::get($formInputs, 'post_update')) {
if (ArrayHelper::get($postUpdateField, 'raw.settings.allow_view_posts') === 'current_user_post') {
if (get_post_field('post_author', $postData['ID']) != get_current_user_id()) {
$status = false;
}
}
}
return $status;
}
public function parsePostShortCodes($property, $parser)
{
$entry = $parser::getEntry();
$entryId = $entry->id;
$postIdObject = wpFluent()->table('fluentform_submission_meta')
->select(['value'])
->where(
[
'response_id' => $entryId,
'meta_key' => '__postFeeds_created_id'
]
)
->first();
$post = get_post($postIdObject->value);
if (!$post) {
return '';
}
if ($property == 'ID') {
return $post->ID;
} elseif ($property == 'post_title') {
return $post->post_title;
} elseif ($property == 'post_permalink') {
return get_permalink($post);
}
return '';
}
}