HEX
Server: Apache/2.4.68 (Debian)
System: Linux as-cs-widget-demo-us-central1 6.1.0-44-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.164-1 (2026-03-09) x86_64
User: root (0)
PHP: 8.2.32
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/wp-recipe-maker/includes/admin/import/class-wprm-import-create.php
<?php
/**
 * Responsible for importing MV Create recipes.
 *
 * @link       https://bootstrapped.ventures
 * @since      5.4.0
 *
 * @package    WP_Recipe_Maker
 * @subpackage WP_Recipe_Maker/includes/admin/import
 */

/**
 * Responsible for importing MV Create recipes.
 *
 * @since      5.4.0
 * @package    WP_Recipe_Maker
 * @subpackage WP_Recipe_Maker/includes/admin/import
 * @author     Brecht Vandersmissen <brecht@bootstrapped.ventures>
 */
class WPRM_Import_Create extends WPRM_Import {
	/**
	 * Get the UID of this import source.
	 *
	 * @since    5.4.0
	 */
	public function get_uid() {
		return 'create';
	}

	/**
	 * Whether or not this importer requires a manual search for recipes.
	 *
	 * @since    5.4.0
	 */
	public function requires_search() {
		return false;
	}

	/**
	 * Get the name of this import source.
	 *
	 * @since    5.4.0
	 */
	public function get_name() {
		return 'MV Create';
	}

	/**
	 * Get HTML for the import settings.
	 *
	 * @since    5.4.0
	 */
	public function get_settings_html() {
		return '';
	}

	/**
	 * Get the total number of recipes to import.
	 *
	 * @since    5.4.0
	 */
	public function get_recipe_count() {
		return count( $this->get_recipes() );
	}

	/**
	 * Get a list of recipes that are available to import.
	 *
	 * @since    5.4.0
	 * @param	 int $page Page of recipes to get.
	 */
	public function get_recipes( $page = 0 ) {
		$recipes = array();

		global $wpdb;
		$table = $wpdb->prefix . 'mv_creations';

		$mv_recipes = array();
		if ( $table === $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) ) {
			$mv_recipes = $wpdb->get_results( $wpdb->prepare(
				"SELECT id, object_id, title, type FROM `%1s`
				WHERE type IN ('recipe','diy')",
				array(
					$table,
				)
			) );
		}

		foreach ( $mv_recipes as $mv_recipe ) {
			if ( WPRM_POST_TYPE !== get_post_type( $mv_recipe->object_id ) ) {
				$recipes[ $mv_recipe->id ] = array(
					'name' => $mv_recipe->title,
					'url' => admin_url( 'post.php?action=edit&id=' . intval( $mv_recipe->id ) . '&post=' . intval( $mv_recipe->object_id ) . '&post_type=mv_create&type=' . urlencode( $mv_recipe->type ) ),
				);
			}
		}

		return $recipes;
	}

	/**
	 * Search the list of recipes that are available to import.
	 *
	 * @since    8.2.0
	 * @param	 string $search Search term to use.
	 */
	public function get_recipes_search( $search ) {
		$recipes = array();

		global $wpdb;
		$table = $wpdb->prefix . 'mv_creations';

		$mv_recipes = array();
		if ( $table === $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) ) {
			$mv_recipes = $wpdb->get_results( $wpdb->prepare(
				"SELECT id, object_id, title, type FROM `%1s`
				WHERE type IN ('recipe','diy')
				AND title LIKE %s",
				array(
					$table,
					'%' . $wpdb->esc_like( $search ) . '%',
				)
			) );
		}

		foreach ( $mv_recipes as $mv_recipe ) {
			if ( WPRM_POST_TYPE !== get_post_type( $mv_recipe->object_id ) ) {
				$recipes[ $mv_recipe->id ] = array(
					'name' => $mv_recipe->title,
					'url' => admin_url( 'post.php?action=edit&id=' . intval( $mv_recipe->id ) . '&post=' . intval( $mv_recipe->object_id ) . '&post_type=mv_create&type=' . urlencode( $mv_recipe->type ) ),
				);
			}
		}

		return $recipes;
	}

	/**
	 * Get recipe with the specified ID in the import format.
	 *
	 * @since    5.4.0
	 * @param	 mixed $id ID of the recipe we want to import.
	 * @param	 array $post_data POST data passed along when submitting the form.
	 */
	public function get_recipe( $id, $post_data ) {
		global $wpdb;
		$table = $wpdb->prefix . 'mv_creations';

		$mv_recipe = false;
		if ( $table === $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) ) {
			$rows = $wpdb->get_results( $wpdb->prepare(
				"SELECT * FROM `%1s`
				WHERE id = %d",
				array(
					$table,
					$id,
				)
			) );

			if ( is_array( $rows ) && 1 === count( $rows ) ) {
				$mv_recipe = (array) $rows[0];
			}
		}

		// Make sure we found the corresponding recipe, die otherwise.
		if ( false === $mv_recipe ) {
			wp_die( 'Could not find the MV table or recipe.' );
		}

		$post_id = isset( $mv_recipe['object_id'] ) ? intval( $mv_recipe['object_id'] ) : 0;

		$recipe = array(
			'import_id' => $post_id,
			'import_backup' => array(
				'mv_creation_id' => $id,
			),
		);

		// Recipe type.
		$recipe['type'] = 'diy' === $mv_recipe['type'] ? 'howto' : 'food';

		// Featured Image.
		$recipe['image_id'] = $mv_recipe['thumbnail_id'];

		// Simple Matching.
		$recipe['name'] = $mv_recipe['title'];
		$recipe['summary'] = $mv_recipe['description'];
		$recipe['cost'] = $mv_recipe['estimated_cost'];
		$recipe['author_name'] = $mv_recipe['author'];

		if ( $recipe['author_name'] ) {
			$recipe['author_display'] = 'custom';
		}

		// Servings.
		$mv_yield = $mv_recipe['yield'];

		$servings = '';
		$servings_unit = '';

		if ( $mv_yield ) {
			$match = preg_match( '/^\s*\d+/', $mv_yield, $servings_array );
			if ( 1 === $match ) {
				$servings = str_replace( ' ','', $servings_array[0] );
			}

			$servings_unit = preg_replace( '/^\s*\d+\s*/', '', $mv_yield );
		}

		$recipe['servings'] = $servings;
		$recipe['servings_unit'] = $servings_unit;

		// Recipe times. From seconds to minutes.
		$recipe['prep_time'] = intval( $mv_recipe['prep_time'] ) / 60;
		$recipe['cook_time'] = intval( $mv_recipe['active_time'] ) / 60;
		$recipe['custom_time'] = intval( $mv_recipe['additional_time'] ) / 60;
		$recipe['custom_time_label'] = $mv_recipe['additional_time_label'];
		$recipe['total_time'] = intval( $mv_recipe['total_time'] ) / 60;

		// Recipe tags.
		$recipe['tags'] = array();
		$recipe['tags']['keyword'] = $mv_recipe['keywords'] ? array_map( 'trim', explode( ',', $mv_recipe['keywords'] ) ) : array();
		$recipe['tags']['suitablefordiet'] = $mv_recipe['suitable_for_diet'] ? array_map( 'trim', explode( ',', $mv_recipe['suitable_for_diet'] ) ) : array();

		$taxonomies = array(
			'category' => 'course',
			'mv_cuisine' => 'cuisine',
		);

		foreach ( $taxonomies as $mv_tag => $wprm_tag ) {
			$terms = get_the_terms( $post_id, $mv_tag );
			if ( $terms && ! is_wp_error( $terms ) ) {
				foreach ( $terms as $term ) {
					$recipe['tags'][ $wprm_tag ][] = $term->name;
				}
			}
		}

		// Recipe video.
		if ( $mv_recipe['external_video'] ) {
			$mv_video = (array) json_decode( $mv_recipe['external_video'] );


			if ( isset( $mv_video['contentUrl'] ) ) {
				$recipe['video_embed'] = $mv_video['contentUrl'];
			}
		} else if ( $mv_recipe['video'] ) {
			$mv_video = (array) json_decode( $mv_recipe['video'] );

			if ( $mv_video['key'] ) {
				$key = esc_attr( $mv_video['key'] );
				$recipe['video_embed'] = '<div id="' . $key . '"></div><script type="text/javascript" src="//video.mediavine.com/videos/' . $key . '.js" async data-noptimize></script>';
			}
		}

		// Pinterest Image.
		if ( $mv_recipe['pinterest_img_id'] ) {
			$recipe['pin_image_id'] = intval( $mv_recipe['pinterest_img_id'] );
		}

		// Ingredients.
		$mv_published = (array) json_decode( $mv_recipe['published'] );
		$mv_ingredients = 'food' === $recipe['type'] ? (array) $mv_published['ingredients'] : (array) $mv_published['materials'];
		$ingredients = array();
		$has_ingredient_links = false;

		foreach ( $mv_ingredients as $mv_group_name => $mv_group_ingredients ) {
			$group = array(
				'name' => 'mv-has-no-group' === $mv_group_name ? '' : $mv_group_name,
				'ingredients' => array(),
			);

			foreach ( $mv_group_ingredients as $mv_ingredient ) {
				$mv_ingredient = (array) $mv_ingredient;
				$text = trim( $mv_ingredient['original_text'] );

				if ( ! empty( $text ) ) {
					$ingredient = array(
						'raw' => $text,
					);

					// Check for ingredient link.
					if ( $mv_ingredient['link'] ) {
						$ingredient['link'] = array(
							'url' => $mv_ingredient['link'],
							'nofollow' => '0' === $mv_ingredient['nofollow'] ? 'follow' : 'nofollow',
						);
						$has_ingredient_links = true;

						// Remove square brackets, used to indicate link.
						$ingredient['raw'] = preg_replace( '/\[(.*)\]/', '$1', $ingredient['raw'] );
					}

					$group['ingredients'][] = $ingredient;
				}
			}

			$ingredients[] = $group;
		}
		$recipe['ingredients'] = $ingredients;

		if ( $has_ingredient_links ) {
			$recipe['ingredient_links_type'] = 'custom';
		}

		// Equipment.
		$mv_equipment = isset( $mv_published['tools'] ) ? (array) $mv_published['tools'] : array();
		$equipment = array();

		foreach ( $mv_equipment as $mv_group_name => $mv_group_equipment ) {
			foreach ( $mv_group_equipment as $mv_item ) {
				$mv_item = (array) $mv_item;
				$text = trim( $mv_item['original_text'] );

				if ( ! empty( $text ) ) {
					$equipment[] = array(
						'name' => $text,
					);
				}
			}
		}

		// Products if tools are not set.
		if ( ! $equipment ) {
			$mv_products = (array) $mv_published['products'];

			foreach ( $mv_products as $mv_product ) {
				$text = trim( $mv_product->title );

				if ( ! empty( $text ) ) {
					$equipment[] = array(
						'name' => $text,
					);

					// Import link and image if not already set.
					$equipment_id = WPRM_Recipe_Sanitizer::get_equipment_id( $text );

					if ( $equipment_id ) {
						$link = $mv_product->link;
						$existing_link = get_term_meta( $equipment_id, 'wprmp_equipment_link', true );

						if ( ! $existing_link && $link ) {
							update_term_meta( $equipment_id, 'wprmp_equipment_link', $link );
						}

						$image_id = intval( $mv_product->thumbnail_id );
						$existing_image_id = get_term_meta( $equipment_id, 'wprmp_equipment_image_id', true );

						if ( ! $existing_image_id && $image_id ) {
							update_term_meta( $equipment_id, 'wprmp_equipment_image_id', $image_id );
						}
					}
				}
			}
		}

		$recipe['equipment'] = $equipment;

		// Instructions.
		$mv_instructions = $this->parse_blob( $mv_recipe['instructions'] );
		$instructions = array();

		foreach ( $mv_instructions as $mv_group ) {
			$group = array(
				'name' => trim( strip_tags( $mv_group['name'], '<a><strong><b><em><i><u><sub><sup>' ) ),
				'instructions' => array(),
			);

			foreach ( $mv_group['items'] as $mv_item ) {
				$text = trim( strip_tags( $mv_item, '<a><strong><b><em><i><u><sub><sup><br>' ) );

				// Find any images and remove from instructions.
				preg_match_all( '/\[mv_img[^\]]*\]/i', $mv_item, $img_shortcodes );
				$text = preg_replace( '/\[mv_img[^\]]*\]/i', '', $text );

				foreach ( $img_shortcodes[0] as $img_shortcode ) {
					$img_shortcode = html_entity_decode( $img_shortcode );
					preg_match( '/id="?\'?(\d+)/i', $img_shortcode, $img );

					if ( $img[1] ) {
						$image_id = intval( $img[1] );

						if ( $image_id ) {
							$group['instructions'][] = array(
								'text' => $text,
								'image' => $image_id,
							);
							$text = ''; // Only add same text once.
						}
					}
				}

				if ( ! empty( $text ) ) {
					$group['instructions'][] = array(
						'text' => $text,
					);
				}
			}

			$instructions[] = $group;
		}
		$recipe['instructions'] = $instructions;

		// Nutrition Facts.
		$recipe['nutrition'] = array();

		$mv_nutrition = (array) $mv_published['nutrition'];

		// Serving size.
		$mv_serving_size = isset( $mv_nutrition['serving_size'] ) ? trim( $mv_nutrition['serving_size'] ) : '';
		$match = preg_match( '/^\s*\d+/', $mv_serving_size, $servings_array );
		if ( 1 === $match ) {
			$servings = str_replace( ' ','', $servings_array[0] );
		} else {
			$servings = '';
		}

		$servings_unit = preg_replace( '/^\s*\d+\s*/', '', $mv_serving_size );

		$recipe['nutrition']['serving_size'] = $servings;
		$recipe['nutrition']['serving_unit'] = $servings_unit;

		// Other nutrients.
		$nutrition_mapping = array(
			'calories'              => 'calories',
			'carbohydrates'         => 'carbohydrates',
			'protein'               => 'protein',
			'total_fat'             => 'fat',
			'saturated_fat'         => 'saturated_fat',
			'unsaturated_fat'   	=> 'polyunsaturated_fat',
			'trans_fat'             => 'trans_fat',
			'cholesterol'           => 'cholesterol',
			'sodium'                => 'sodium',
			'fiber'                 => 'fiber',
			'sugar'                 => 'sugar',
			'sugar_alcohols'        => 'sugar_alcohols',
		);

		foreach ( $nutrition_mapping as $mv_field => $wprm_field ) {
			if ( isset( $mv_nutrition[ $mv_field ] ) && $mv_nutrition[ $mv_field ] ) {
				$recipe['nutrition'][ $wprm_field ] = $mv_nutrition[ $mv_field ];
			}
		}

		// Recipe Notes.
		$notes = $mv_recipe['notes'];

		// Find any images.
		preg_match_all( '/\[mv_img[^\]]*\]/i', $notes, $img_shortcodes );

		foreach ( $img_shortcodes[0] as $img_shortcode_encoded ) {
			$img_shortcode = html_entity_decode( $img_shortcode_encoded );
			preg_match( '/id="?\'?(\d+)/i', $img_shortcode, $img );

			if ( $img[1] ) {
				$image_id = intval( $img[1] );

				if ( $image_id ) {
					$image_html = wp_get_attachment_image( $image_id, 'medium' );

					if ( $image_html ) {
						$notes = str_replace( $img_shortcode_encoded, $image_html, $notes );
					}
				}
			}
		}

		$recipe['notes'] = $notes;

		return $recipe;
	}

	/**
	 * Replace the original recipe with the newly imported WPRM one.
	 *
	 * @since    5.4.0
	 * @param	 mixed $id ID of the recipe we want replace.
	 * @param	 mixed $wprm_id ID of the WPRM recipe to replace with.
	 * @param	 array $post_data POST data passed along when submitting the form.
	 */
	public function replace_recipe( $id, $wprm_id, $post_data ) {
		global $wpdb;
		$table = $wpdb->prefix . 'mv_creations';

		$mv_recipe = false;
		if ( $table === $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) ) {
			$rows = $wpdb->get_results( $wpdb->prepare(
				"SELECT * FROM `%1s`
				WHERE id = %d",
				array(
					$table,
					$id,
				)
			) );

			if ( is_array( $rows ) && 1 === count( $rows ) ) {
				$mv_recipe = (array) $rows[0];
			}
		}

		// Make sure we found the corresponding recipe, die otherwise.
		if ( false === $mv_recipe ) {
			wp_die( 'Could not find the MV table or recipe.' );
		}

		// Get all associated posts.
		$post_ids = json_decode( $mv_recipe['associated_posts'] );
		foreach ( $post_ids as $post_id ) {
			$post = get_post( $post_id );
			$content = $post->post_content;

			// Gutenberg.
			$gutenberg_matches = array();
			if ( 'diy' === $mv_recipe['type'] ) {
				$gutenberg_patern = '/<!--\s+wp:(mv\/diy)(\s+(\{.*?\}))?\s+(\/)?-->.*?<!--\s+\/wp:mv\/diy\s+(\/)?-->/mis';
			} else {
				$gutenberg_patern = '/<!--\s+wp:(mv\/recipe)(\s+(\{.*?\}))?\s+(\/)?-->.*?<!--\s+\/wp:mv\/recipe\s+(\/)?-->/mis';
			}
			preg_match_all( $gutenberg_patern, $content, $matches );

			if ( isset( $matches[3] ) ) {
				foreach ( $matches[3] as $index => $block_attributes_json ) {
					if ( ! empty( $block_attributes_json ) ) {
						$attributes = json_decode( $block_attributes_json, true );

						if ( ! is_null( $attributes ) ) {
							if ( isset( $attributes['id'] ) && intval( $id ) === intval( $attributes['id'] ) ) {
								$content = str_ireplace( $matches[0][ $index ], '<!-- wp:wp-recipe-maker/recipe {"id":' . $wprm_id . ',"updated":' . time() . '} -->[wprm-recipe id="' . $wprm_id . '"]<!-- /wp:wp-recipe-maker/recipe -->', $content );
							}
						}
					}
				}
			}

			// Classic Editor.
			$classic_pattern = '/\[mv_create\s.*?key=\"?\'?(\d+)\"?\'?.*?\]/mi';
			preg_match_all( $classic_pattern, $content, $classic_matches );

			if ( isset( $classic_matches[1] ) ) {
				foreach ( $classic_matches[1] as $index => $mv_id ) {
					if ( $id === $mv_id ) {
						$content = str_ireplace( $classic_matches[0][ $index ], '[wprm-recipe id="' . $wprm_id . '"]', $content );
					}
				}
			}

			// Classic Editor Deprecated Shortcode.
			$classic_pattern = '/\[mv_recipe\s.*?post_id=\"?\'?(\d+)\"?\'?.*?\]/mi';
			preg_match_all( $classic_pattern, $content, $classic_matches );

			if ( isset( $classic_matches[1] ) ) {
				foreach ( $classic_matches[1] as $index => $mv_id ) {
					if ( $mv_recipe['original_object_id'] === $mv_id ) {
						$content = str_ireplace( $classic_matches[0][ $index ], '[wprm-recipe id="' . $wprm_id . '"]', $content );
					}
				}
			}

			// Update post with new content including our shortcodes.
			if ( $content !== $post->post_content ) {
				$update_content = array(
					'ID' => $post_id,
					'post_content' => wp_slash( $content ),
				);
				wp_update_post( $update_content );
			}
		}

		// Migrate ratings.
		$table = $wpdb->prefix . 'mv_reviews';

		$mv_ratings = false;
		if ( $table === $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) ) {
			$rows = $wpdb->get_results( $wpdb->prepare(
				"SELECT * FROM `%1s`
				WHERE creation = %d",
				array(
					$table,
					$id,
				)
			) );

			if ( is_array( $rows ) ) {
				$mv_ratings = (array) $rows;
			}
		}

		if ( $mv_ratings ) {
			foreach ( $mv_ratings as $mv_rating ) {
				$mv_rating = (array) $mv_rating;

 				$rating = array(
					'recipe_id' => $wprm_id,
					'user_id' => '',
					'ip' => 'mediavine-create-' . $mv_rating['id'],
					'rating' => ceil( floatval( $mv_rating['rating'] ) ),
					'date' => $mv_rating['created'],
				);

				WPRM_Rating_Database::add_or_update_rating( $rating );
			}
		}
	}

	/**
	 * Blob to array.
	 *
	 * @since    5.4.0
	 * @param	 mixed $blob Blob to parse.
	 */
	private function parse_blob( $blob ) {
		$component_list = array();
		$component_group = array(
			'name' => '',
			'items' => array(),
		);

		// Split in different parts.
		$blob = preg_replace( '/<ol(\s[^>]*>|>)/mi', '$0' . PHP_EOL, $blob );
		$blob = str_ireplace( '</li>', '</li>' . PHP_EOL, $blob );
		$blob = str_ireplace( '</ol>', '</ol>' . PHP_EOL, $blob );
		$blob = str_ireplace( '</h3>', '</h3>' . PHP_EOL, $blob );
		$blob = str_ireplace( '</p>', '</p>' . PHP_EOL, $blob );

		$bits = explode( PHP_EOL, $blob );
		foreach ( $bits as $bit ) {

			$test_bit = trim( $bit );
			if ( empty( $test_bit ) ) {
				continue;
			}

			if ( WPRM_Import_Helper::is_heading( $bit ) ) {
				$component_list[] = $component_group;

				$component_group = array(
					'name' => $bit,
					'items' => array(),
				);
			} else {
				$component_group['items'][] = $bit;
			}
		}

		$component_list[] = $component_group;

		return $component_list;
	}
}