check_product_status( $post_data['nodes'] ); $post_data['nodes'] = $new_node; } $post_data['data_is_converted'] = false; if ( empty( $post_data['nodes'] ) && ! empty( $post_data['sellkit_steps'] ) ) { $nodes = self::convert_steps_to_nodes( $post_data['sellkit_steps'] ); update_post_meta( $post_id, 'nodes', $nodes ); delete_post_meta( $post_id, 'sellkit_steps' ); unset( $post_data['sellkit_steps'] ); $post_data['nodes'] = $nodes; $post_data['data_is_converted'] = true; } $post_data['sellkit_post_title'] = html_entity_decode( get_the_title( $post_id ) ); $post_data['sellkit_post_slug'] = get_post_field( 'post_name', $post_id ); $post_data['sellkit_post_status'] = get_post_status( $post_id ); // Unset sales-page when user exploring global checkout page. if ( 'checkout' === $page && ! empty( $post_data['nodes'] ) ) { foreach ( $post_data['nodes'] as $key => $step ) { if ( is_array( $step['type'] ) && 'sales-page' === $step['type']['key'] ) { unset( $post_data['nodes']->$key ); } if ( is_object( $step['type'] ) && 'sales-page' === $step['type']->key ) { unset( $post_data['nodes']->$key ); } } } wp_send_json_success( [ 'post_data' => $post_data ] ); } /** * Converts steps to nodes. * * @since 1.5.0 * @param array $steps Steps. */ public static function convert_steps_to_nodes( $steps ) { $nodes = []; $final_steps = $steps; $first_key = array_key_first( $steps ); if ( empty( $steps[ $first_key ]['targets'] ) ) { $final_steps = self::add_decision_node_before_upsells( $steps ); } foreach ( $final_steps as $key => $step ) { $nodes[ $key ] = $step; if ( ! empty( $step['type']->key ) && 'decision' !== $step['type']->key ) { $nodes[ $key ]['targets'] = count( $final_steps ) > $key + 1 ? [ [ 'nodeId' => strval( $key + 1 ) ] ] : []; } if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key && count( $final_steps ) > $key + 1 ) { $nodes[ $key ]['targets'] = [ [ 'nodeId' => strval( $key + 1 ) ], [ 'nodeId' => strval( $key + 1 ) ] ]; } if ( ! empty( $step['type']->key ) && 'decision' === $step['type']->key ) { if ( is_object( $step['targets'][0] ) ) { $step['targets'][0] = (array) $step['targets'][0]; } if ( is_object( $step['targets'][1] ) ) { $step['targets'][1] = (array) $step['targets'][1]; } if ( empty( $final_steps[ $step['targets'][0]['nodeId'] ] ) ) { $nodes[ $key ]['targets'][0] = ''; } if ( empty( $final_steps[ $step['targets'][1]['nodeId'] ] ) ) { $nodes[ $key ]['targets'][1] = ''; } } $nodes[ $key ]['jsx'] = $step['title']; } return (object) $nodes; } /** * Adds decision node before upsells. * * @since 1.5.0 * @param array $steps Steps. */ public static function add_decision_node_before_upsells( $steps ) { $final_steps = []; $upsell_num = 0; foreach ( $steps as $key => $step ) { $step['type'] = (object) $step['type']; $step['data'] = ! empty( $step['data'] ) ? (object) $step['data'] : null; if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key ) { $new_node_id = wp_insert_post( [ 'post_type' => Sellkit_Admin_Steps::SELLKIT_STEP_POST_TYPE, 'post_title' => __( 'Decision', 'sellkit' ), 'post_name' => sanitize_title( __( 'Decision', 'sellkit' ) ), 'post_status' => 'publish', ] ); $type_object = new stdClass(); $type_object->title = esc_html__( 'Decision', 'sellkit' ); $type_object->key = 'decision'; $decision_node = [ 'title' => esc_html__( 'Decision', 'sellkit' ), 'type' => $type_object, 'current_target_index' => 0, 'page_id' => $new_node_id, 'slug' => get_post_field( 'post_name', $new_node_id ), 'funnel_id' => $step['funnel_id'], 'targets' => [ [ 'nodeId' => strval( $key + 1 + $upsell_num ) ], [ 'nodeId' => strval( $key + 2 + $upsell_num ) ] ], 'data' => [ 'conditions' => ! empty( $step['data']->conditions ) ? $step['data']->conditions : [] ] ]; update_post_meta( $new_node_id, 'step_data', $decision_node ); $final_steps[] = $decision_node; $upsell_num++; } $final_steps[] = $step; } return $final_steps; } /** * Save post. * * @since 1.1.0 */ public function save_post() { check_ajax_referer( 'sellkit', 'nonce' ); $fields = sellkit_post( 'fields' ); $post_id = sellkit_htmlspecialchars( INPUT_POST, 'post_id' ); $post_type = sellkit_htmlspecialchars( INPUT_POST, 'post_type' ); $this->sub_action = sellkit_htmlspecialchars( INPUT_POST, 'sub_action' ); $this->page = sellkit_htmlspecialchars( INPUT_POST, 'page' ); $sanitized_fields = $this->sanitize_fields( $fields ); $this->validate_fields( $sanitized_fields ); $target_post_id = $this->handle_save_post( $sanitized_fields, $post_type, $post_id ); if ( empty( $target_post_id ) ) { wp_send_json_error( [ __( 'something went wrong', 'sellkit' ) ] ); } if ( $post_id ) { wp_send_json_success( [ 'post_id' => $post_id, 'message' => __( 'The update process has been completed.', 'sellkit' ), ] ); } wp_send_json_success( [ 'post_id' => $target_post_id, 'message' => __( 'The creation process has been completed.', 'sellkit' ), ] ); } /** * Update or add new post. * * @param array $data All data. * @param string $post_type The post type. * @param bool $post_id The post Id. * @return bool|integer * * @since 1.1.0 * @SuppressWarnings(PHPMD.NPathComplexity) */ private function handle_save_post( $data, $post_type, $post_id = false ) { $title = sanitize_text_field( $data['sellkit_post_title'] ); $slug = ! empty( $data['sellkit_post_slug'] ) ? sanitize_text_field( $data['sellkit_post_slug'] ) : ''; $post_status = 'publish' === $data['sellkit_post_status'] ? 'publish' : 'draft'; if ( isset( $data['sellkit_global_checkout_header_footer_templates'] ) && 'checkout' === $this->page ) { unset( $data['sellkit_global_checkout_header_footer_templates'] ); } $post_args = [ 'post_title' => $title, 'post_name' => $slug ?: sanitize_title( $title ), 'post_type' => $post_type, 'post_status' => $post_status, ]; if ( ! $post_id ) { $new_post_id = wp_insert_post( $post_args ); } if ( $post_id ) { $post_args = array_merge( $post_args, [ 'ID' => $post_id ] ); $new_post_id = wp_update_post( $post_args ); do_action( "sellkit_posts_after_saving_$post_type", $post_id ); } if ( empty( $new_post_id ) || is_wp_error( $new_post_id ) ) { return false; } foreach ( $data as $name => $value ) { if ( 'sellkit_post_title' === $name || 'sellkit_post_status' === $name ) { continue; } update_post_meta( $new_post_id, $name, $value ); if ( 'sellkit_steps' === $name || 'nodes' === $name ) { do_action( 'sellkit_funnels_update_steps', $value, $new_post_id ); } } if ( empty( $data['conditions'] ) ) { delete_post_meta( $new_post_id, 'conditions' ); } do_action( "sellkit_funnels_after_$this->sub_action", $post_id ); if ( empty( $data['sellkit_steps'] ) ) { delete_post_meta( $new_post_id, 'sellkit_steps' ); } if ( empty( $data['nodes'] ) ) { delete_post_meta( $new_post_id, 'nodes' ); } if ( 'checkout' === $this->page ) { update_option( 'sellkit_global_checkout_id', $new_post_id ); } return $new_post_id; } /** * Sanitize fields. * * @param array $fields Fields. * * @return array * * @since 1.1.0 */ private function sanitize_fields( $fields ) { $new_fields = []; foreach ( $fields as $key => $field ) { if ( is_array( $fields[ $key ] ) ) { $new_fields[ $key ] = $this->sanitize_fields( $fields[ $key ] ); } $field_value = sanitize_meta( $key, $field, 'post' ); if ( ! is_array( $fields[ $key ] ) ) { $new_fields[ $key ] = $field_value; } } if ( ! empty( $new_fields['conditions'] ) ) { $new_fields['conditions'] = sellkit_condition_row_sanitization( $new_fields['conditions'] ); } if ( ! empty( $new_fields['filters'] ) ) { $new_fields['filters'] = sellkit_filter_row_sanitization( $new_fields['filters'] ); } return $new_fields; } /** * Validate fields. * * @param array $fields Fields. * * @since 1.1.0 */ public function validate_fields( $fields ) { $errors = []; if ( empty( $fields['sellkit_post_title'] ) ) { $errors[] = __( 'Post title should not be empty.', 'sellkit' ); } if ( empty( $errors ) ) { return; } wp_send_json_error( $errors ); } /** * Check product status * * @param mixed $nodes List of node data. * @since 1.7.9 * @return array */ public function check_product_status( $nodes ) { $nodes = (object) unserialize( $nodes ); // phpcs:ignore WordPress.PHP $new_node = []; if ( ! class_exists( 'WooCommerce' ) ) { return $new_node; } foreach ( $nodes as $index => $node ) { if ( ! empty( $node['page_id'] ) ) { $node['link'] = get_the_permalink( $node['page_id'] ); } if ( 'checkout' !== $node['type']['key'] ) { $new_node[ $index ] = $node; continue; } if ( ! empty( $node['data']['products'] ) && ! empty( $node['data']['products']['list'] ) ) { foreach ( $node['data']['products']['list'] as $key => $product ) { $product_obj = wc_get_product( $key ); if ( empty( $product_obj ) ) { unset( $node['data']['products']['list'][ $key ] ); } $data = ! empty( $product_obj ) ? $product_obj->get_data() : []; if ( ! empty( $data['status'] ) && 'trash' === $data['status'] ) { unset( $node['data']['products']['list'][ $key ] ); } } } $new_node[ $index ] = $node; } if ( empty( $new_node ) ) { return $node; } return $new_node; } } Sellkit_Admin_Posts::get_instance();