<?php
/*
 * Plugin Name:Wordpress Auto Spinner - Post Rewriter
 * Plugin URI: http://codecanyon.net/item/wordpress-auto-spinner-articles-rewriter/4092452?ref=ValvePress
 * Description: Automatically rewrite your articles to create fresh content.
 * Version: 3.26.0
 * Author: ValvePress
 * Author URI: http://codecanyon.net/user/ValvePress/portfolio?ref=ValvePress
 */
update_option('wp_auto_spinner_license', 'activated');
update_option('wp_auto_spinner_license_active', 'active');
update_option('wp_auto_spinner_license_active_date', time());
/* Copyright 2012-2024 Wordpress Auto Spinner - Wordpress Rewriter Plugin (email : sweetheatmn@gmail.com) */
define ( 'WP_VALVE_PROXY', false );

//const number of chars to split the text to for OpenAI non English languages defaults to 1000
define ('WP_AUTO_SPINNER_OPENAI_NON_ENGLISH_LIMIT', 4000 );

//english language limit
define ('WP_AUTO_SPINNER_OPENAI_ENGLISH_LIMIT', 8000 );

//const number of queue retries, this is how many times the plugin pull the same post and try to 
//rewrite before removing from the queue if failed all tries
//defaults to 5
define ('WP_AUTO_SPINNER_QUEUE_RETRIES', 5 );

//default title prompt 
define ('WP_AUTO_SPINNER_OPENAI_TITLE_PROMPT', 'Rewrite this title to be unique and engaging. return a single title only without any comments.');

//default openai model 
define ('WP_AUTO_SPINNER_OPENAI_MODEL', 'gpt-4o-mini');

//default openrouter model 'meta-llama/llama-3-8b-instruct:free'
//updated to meta-llama/llama-3.3-70b-instruct:free on 18/05/2025
define ('WP_AUTO_SPINNER_OPENROUTER_MODEL', 'meta-llama/llama-3.3-70b-instruct:free');

/*
 * Editor stylesheets
 */
function wp_auto_spinner_mce_css($mce_css) {
	if (! empty ( $mce_css ))
		$mce_css .= ',';
	
	$mce_css .= plugins_url ( 'css/style.editor.css', __FILE__ );
	
	return $mce_css;
}

add_filter ( 'mce_css', 'wp_auto_spinner_mce_css' );

/*
 * ------------------------------------------------------------------------*
 * Function Selected
 * ------------------------------------------------------------------------
 */
if (! function_exists ( 'opt_selected' )) {
	function opt_selected($src, $val) {
		if (trim ( $src ) == trim ( $val ))
			echo ' selected="selected" ';
	}
}

/* Add a new meta box to the admin menu. */
add_action ( 'admin_menu', 'wp_auto_spinner_create_meta_box' );

/**
 * Function for adding meta boxes to the admin.
 */
function wp_auto_spinner_create_meta_box() {
	$wp_spinner_types = get_option ( 'wp_spinner_types', array (
			'post',
			'product' 
	) );
	
	foreach ( $wp_spinner_types as $type ) {
		
		add_meta_box ( 'wp_auto_spinner-meta-boxes', 'Wordpress Auto Spinner ', 'wp_auto_spinner_meta_boxes', $type, 'normal', 'high' );
	}
}
function wp_auto_spinner_meta_boxes() {
	require_once ('meta.php');
	wp_auto_spinner_metabox ();
}
 


/**
 * Function for adding header style sheets and js
 */
function wp_auto_spinner_admin_head() {
	echo '<link rel="stylesheet" type="text/css" href="' . plugins_url ( 'css/style.wpautospinner.css', __FILE__ ) . '" />';
	echo '<script src="' . plugins_url ( 'js/main.wpautospinner.js?v=1.9.5', __FILE__ ) . '" type="text/javascript"></script>';
}
add_action ( 'admin_head-post-new.php', 'wp_auto_spinner_admin_head' );
add_action ( 'admin_head-post.php', 'wp_auto_spinner_admin_head' );
function wp_auto_spinner_load_custom_admin_styles() {
	wp_register_style ( 'wp_auto_spinner_custom_dashicons', plugins_url ( 'css/dashicon-styles.css', __FILE__ ), false, '1.0.0' );
	wp_enqueue_style ( 'wp_auto_spinner_custom_dashicons' );
}

add_action ( 'admin_enqueue_scripts', 'wp_auto_spinner_load_custom_admin_styles' );

// settings page
function wp_auto_spinner_admin_head_options() {
	echo '<link rel="stylesheet" type="text/css" href="' . plugins_url ( 'css/style.wpautospinner.css', __FILE__ ) . '">';
	echo '<script src="' . plugins_url ( 'js/options.wpautospinner.js', __FILE__ ) . '" type="text/javascript"></script>';
}
add_action ( 'admin_head-wp_auto_spinner_settings', 'wp_auto_spinner_admin_head_options' );

// synonyms page
function wp_auto_spinner_admin_head_synonyms() {
	echo '<link rel="stylesheet" type="text/css" href="' . plugins_url ( 'css/synonyms.wpautospinner.css', __FILE__ ) . '">';
	echo '<script src="' . plugins_url ( 'js/synonyms.wpautospinner.js', __FILE__ ) . '" type="text/javascript"></script>';
}
function wp_auto_spinner_admin_head_thesaurus() {
	echo '<link rel="stylesheet" type="text/css" href="' . plugins_url ( 'css/synonyms.wpautospinner.css', __FILE__ ) . '">';
	echo '<script src="' . plugins_url ( 'js/thesaurus.wpautospinner.js', __FILE__ ) . '" type="text/javascript"></script>';
}

// edit page
add_action ( 'admin_print_scripts-' . 'edit.php', 'wp_auto_spinner_admin_edit' );

// bulk pin scripts
function wp_auto_spinner_admin_edit() {
	wp_enqueue_script ( 'wp_auto_spinner_bulk_spin', plugins_url ( '/js/bulk-spin.js?v=1.0.0', __FILE__ ) );
}

/*
 * Function to add menu settings page
 */
add_action ( 'admin_menu', 'wp_auto_spinner_control_menu' );
function wp_auto_spinner_control_menu() {
	// add_submenu_page('options-general.php', 'wp_auto_spinner-control', 'wp_auto_spinner control', 'manage_options', 'wp_auto_spinner-control-menu', 'wp_auto_spinner_control_options');
	// add_menu_page( 'WP spinner Synonyms', 'WP Spinner', 'administrator', 'wp_auto_spinner', 'wp_auto_spinner_synonyms_fn', plugins_url('images/spin.png',__FILE__), 77777787777777 );
	add_menu_page ( 'WP spinner Synonyms', 'Auto Spinner', 'administrator', 'wp_auto_spinner', 'wp_auto_spinner_synonyms_fn', 'dashicons-wp-spinner-pencil-square-o', 77777787777777 );
	
	$synonymsSlug = add_submenu_page ( 'wp_auto_spinner', 'Wp Auto Spinner synonyms', 'Thesaurus', 'administrator', 'wp_auto_spinner', 'wp_auto_spinner_synonyms_fn' );
	add_action ( 'admin_head-' . $synonymsSlug, 'wp_auto_spinner_admin_head_synonyms' );
	
	$synonymsSlug = add_submenu_page ( 'wp_auto_spinner', 'Wp Auto Spinner custom thesaurus', 'My thesaurus', 'administrator', 'wp_auto_spinner_thesaurus', 'wp_auto_spinner_thesaurus' );
	add_action ( 'admin_head-' . $synonymsSlug, 'wp_auto_spinner_admin_head_thesaurus' );
	
	add_submenu_page ( 'wp_auto_spinner', 'Wp Auto Spinner settings', 'Settings', 'administrator', 'wp_auto_spinner_settings', 'wp_auto_spinner_fn' );
	
	$queueSlug = add_submenu_page ( 'wp_auto_spinner', 'Wp Auto Spinner Spinning Queue', 'Queue', 'administrator', 'wp_auto_spinner_queue', 'wp_auto_spinner_queue' );
	add_action ( 'admin_head-' . $queueSlug, 'wp_auto_spinner_admin_head_log' );
	
	$logSlug = add_submenu_page ( 'wp_auto_spinner', 'Wp Auto Spinner Log', 'Log', 'administrator', 'wp_auto_spinner_log', 'wp_auto_spinner_log' );
	add_action ( 'admin_head-' . $logSlug, 'wp_auto_spinner_admin_head_log' );
}
function wp_auto_spinner_admin_head_log() {
	echo '<link rel="stylesheet" type="text/css" href="' . plugins_url ( 'css/style.log.css', __FILE__ ) . '">';
	echo '<script src="' . plugins_url ( 'js/log.js', __FILE__ ) . '" type="text/javascript"></script>';
}
function wp_auto_spinner_synonyms_fn() {
	require_once (dirname ( __FILE__ ) . '/synonyms.php');
	wp_auto_spinner_synonyms ();
}
function wp_auto_spinner_thesaurus() {
	require_once (dirname ( __FILE__ ) . '/thesaurus.php');
	wp_auto_spinner_thesaurus_f ();
}
function wp_auto_spinner_queue() {
	require_once (dirname ( __FILE__ ) . '/spinner_queue.php');
	wp_auto_spinner_queue_fn ();
}
function wp_auto_spinner_fn() {
	require_once (dirname ( __FILE__ ) . '/options.php');
	wp_auto_spinner_settings ();
}
 

$wp_spinner_types = get_option ( 'wp_spinner_types', array (
		'post',
		'product' 
) );

foreach ( $wp_spinner_types as $type ) {
	
	add_action ( 'publish_' . $type, 'wp_auto_spinner_publish', 1 );
}


/**
 * Function to check if the post is spinned or not if not spinned let's spin it. works on publish
 * Get fired when publishing the post using a bot or manually on the edit post page
 * @param integer $post_id : post id to check
 */
function wp_auto_spinner_publish($post_id) {

	
	// if quick edit mode ignore it .
	if (isset ( $_SERVER ['HTTP_REFERER'] ) && stristr ( $_SERVER ['HTTP_REFERER'], 'edit.php' ))
		return;
	
	// check if an edit of an original post
	if (isset ( $_POST ['save'] ) && trim ( $_POST ['save'] != 'editpost' )) {
		return;
	}

 
	
	global $post;
	
	// check if already checked if yes return
	$checked = get_post_meta ( $post_id, 'wp_auto_spinner_checked', 1 );
	
	if (trim ( $checked ) != '')
		return;
	
	// set checked flag to yes
	update_post_meta ( $post_id, 'wp_auto_spinner_checked', 'yes' );
	

	// New gutenberg UI does not set an $_POST['publish'] variable but $_GET['_locale'] set to user
	//at this case, lets check if loale is set and mock the publish button by setting the $_POST['publish'] variable
	if ( ! isset($_POST ['publish']) && isset ( $_GET ['_locale'] ) && $_GET ['_locale'] == 'user') {
		$_POST ['publish'] = 'Publish';
	}

	// INSTANT SPIN : manual + manual spin enabled or auto + auto spin enabled + spin on publish enabled
	$autospin = get_option ( 'wp_auto_spin', array () );

	 
	if ((isset ( $_POST ['publish'] ) && in_array ( 'OPT_AUTO_SPIN_ACTIVE_MANUAL', $autospin )) || (! isset ( $_POST ['publish'] )) && in_array ( 'OPT_AUTO_SPIN_ACTIVE', $autospin ) && in_array ( 'OPT_AUTO_SPIN_PUBLISH', $autospin )) {
		
		// INSTANT SPIN

		wp_auto_spinner_log_new ( 'New Post >> Publish', 'New post with id {' . $post_id . '} is going to be published and deserve spinning' );
		
		$execl = get_option ( 'wp_auto_spin_execl', array () );
		
		if (in_category ( $execl, $post_id )) {
			
			wp_auto_spinner_log_new ( 'New Post >> Cancel Spin', 'Post in an execluded from spinning category . ignore post .' );
			return;
		} else {
			wp_auto_spinner_post_spin ( $post_id );
		}
	} elseif (! isset ( $_POST ['publish'] ) && in_array ( 'OPT_AUTO_SPIN_ACTIVE', $autospin )) {
		
		// SCHEDULED SPIN

		wp_auto_spinner_log_new ( 'New Post >> Publish', 'New post with id {' . $post_id . '} is going to be published sent to spin queue' );
		
		// add the scheduled spin meta
		update_post_meta ( $post_id, 'wp_auto_spinner_scheduled', 'yes' );
	}
	
	return;
	 
}

/*
 * Spin this post function it gets triggered by the spinner_schedule that process the queue or on publish event 
 * it takes the post ID, read its title and content then rewrite it
 * @post_id: post id to spin
 * return : none
 * 
 */
function wp_auto_spinner_post_spin($post_id) {
	 
	
	// let's spin this post
	// get the post
	$post_arr = get_post ( $post_id );
	
	// spin options
	$autospin = get_option ( 'wp_auto_spin', array () );
	
	$content = $post_arr->post_content;
	$ttl = $post_arr->post_title;
	$originalcontent = $content;
	
	// spin libs
	require_once (dirname ( __FILE__ ) . '/inc/class.spin.php');
	require_once (dirname ( __FILE__ ) . '/inc/class.spintax.php');
	
	// spin start
	$spin = new wp_auto_spin_spin ( $post_id, $ttl, $content );
	$spinned = $spin->spin_wrap ();
	
	//if spinned is boolean and == false, report failure in log
	if ( is_bool($spinned)	&& $spinned == false){

		//log failed rewrite
		wp_auto_spinner_log_new ( 'New Post >> Fail Spin', 'Post with id {' . $post_id . '} failed to be rewritten.' );

		//return 
		return false;
	}

	// spinned cnt
	$spinned_ttl = $spinned ['spinned_ttl'];
	$spinned_cnt = $spinned ['spinned_cnt'];
	$spintaxed_ttl = $spinned ['spintaxed_ttl'];
	$spintaxed_cnt = $spinned ['spintaxed_cnt'];
	$content = $spintaxed_cnt;
	
	// update the post
	$my_post = array ();
	$my_post ['ID'] = $post_id;
	
	if (! in_array ( 'OPT_AUTO_SPIN_DEACTIVE_CNT', $autospin )) {
		$my_post ['post_content'] = $content;
	}
	
	// update spinned title if allowed
	if (in_array ( 'OPT_AUTO_SPIN_ACTIVE_TTL', $autospin )) {
		$my_post ['post_title'] = $spintaxed_ttl;
	}
	
	// check if we should updat the slug .
	if (in_array ( 'OPT_AUTO_SPIN_SLUG', $autospin )) {
		$my_post ['post_name'] = '';
	}
	
	wp_auto_spinner_log_new ( 'New Post >> Do Spin', 'Post with id {' . $post_id . '} spinned successfully .' );
	
	remove_filter ( 'content_save_pre', 'wp_filter_post_kses' );
	
	wp_update_post ( $my_post );
	// add_filter('content_save_pre', 'wp_filter_post_kses');
}

/*
 * differ if the post is manually spinned or not by saving
 */
add_action ( 'save_post', 'wp_auto_spinner_save_meta_data' );
function wp_auto_spinner_save_meta_data($post_id) {

 
	//post type check fix for issue #3
	$post_type = get_post_type($post_id);

	//get supported post types wp_spinner_types
	$wp_spinner_types = get_option('wp_spinner_types',array('post') );

	 //check if the post type is supported
	if (!in_array($post_type, $wp_spinner_types)){
		return;
	}

	 
	// SCHEDULED POSTS TO QUEUE
	if (! wp_is_post_revision ( $post_id )) {

		 
		//post status on classic editor
		//selected post status like publish or draft
		$publish = (isset ( $_POST ['post_status'] )) ? $_POST ['post_status'] : '';

		 
		//check if this is a scheduled post or not 
		$is_scheuled_post = false; //default to false


		if((trim ( $publish ) == 'publish' && isset ( $_POST ['post_date'] ))){

			//Classic editor scheduled post
			$is_scheuled_post = true;

			//check if scheduled on the new UI
			//$_get['_locale'] is set to user when the post is scheduled
			//the request body will be a json on the form 
			/*
			{
    "id": 89512,
    "title": "life is short",
    "date": "2024-05-09T17:12:00",
    "status": "future",
    "content": ""
}
*/
		}elseif (isset($_GET['_locale']) && $_GET['_locale'] == 'user'){

			// fetch params
			$request_body = file_get_contents('php://input');

		 	//if "status": "future" is found in the request body, then this is a scheduled post
		  	
			if (stristr($request_body, '"future"') !== false){
				$is_scheuled_post = true;
			} 
			 
		}


		//plugin options
		$autospin = get_option ( 'wp_auto_spin', array () );
		
		if ($is_scheuled_post) {
			// this is a scheduled post let's schedule for spin if eligible
			
			// check if already checked if yes return
			$checked = get_post_meta ( $post_id, 'wp_auto_spinner_checked', 1 );
			
			if (trim ( $checked ) != '')
				return;
			
			// set checked flag to yes
			update_post_meta ( $post_id, 'wp_auto_spinner_checked', 'yes' );
			
			// if manual enabled schedule
			if (in_array ( 'OPT_AUTO_SPIN_ACTIVE_MANUAL', $autospin )) {
				// schedule it manual post spinning enable
				// SCHEDULED SPIN
				wp_auto_spinner_log_new ( 'New Post >> Schedule', 'New scheduled post with id {' . $post_id . '}   sent to spin queue' );
				
				// add the scheduled spin meta
				update_post_meta ( $post_id, 'wp_auto_spinner_scheduled', 'yes' );
			}
			
			// scheduled post
		} else {
			
			// Draft posts
			// SPIN Draft posts
			$status = get_post_status ( $post_id );
			
			if ($status == 'draft' && trim ( $publish ) == '' && in_array ( 'OPT_AUTO_SPIN_DRAFT', $autospin )) {
				
				$spinned_cnt = get_post_meta ( $post_id, 'spinned_cnt', 1 );
				
				if (trim ( $spinned_cnt ) != '')
					return;
				
				wp_auto_spinner_log_new ( 'New Post >>Draft Schedule', 'New draft post with id {' . $post_id . '}   sent to spin queue' );
				
				// add the scheduled spin meta
				update_post_meta ( $post_id, 'wp_auto_spinner_scheduled', 'yes' );
			}
		}
	} // not revision
}

/**
 * custom request for metabox buttons
 */
function wp_auto_spinner_parse_request($wp) {
	
	// only process requests with "my-plugin=ajax-handler"
	if (array_key_exists ( 'wp_auto_spinner', $wp->query_vars )) {
		
		if ($wp->query_vars ['wp_auto_spinner'] == 'ajax') {

			//check if user is logged in and is admin
			if ( !is_user_logged_in() || !current_user_can( 'administrator' ) ) {
				wp_send_json_error( 'You do not have permission to perform this action.' );
			}
			
			require_once ('p_ajax.php');
			exit ();
		} elseif ($wp->query_vars ['wp_auto_spinner'] == 'cron') {

			//record the current time as the last time the external cron was called
			//option WP_AUTO_SPINNER_EXTERNAL_CRON_TIME
			update_option('WP_AUTO_SPINNER_EXTERNAL_CRON_TIME', time() ); 

			//log an external cron call 
			wp_auto_spinner_spin_function ();

			exit ();
		} elseif ($wp->query_vars ['wp_auto_spinner'] == 'test') {
			require_once 'test.php';
			exit ();
		} elseif ($wp->query_vars ['wp_auto_spinner'] == 'backup_synonyms') {
			require_once 'backup_synonyms.php';
			exit ();
		}
	}
}
add_action ( 'parse_request', 'wp_auto_spinner_parse_request' );

add_action ( 'wp_ajax_wp_auto_spinner_ajax', 'wp_auto_spinner_ajax_callback' );
function wp_auto_spinner_ajax_callback() {
	require_once 'p_ajax.php';
	die ();
}
function wp_auto_spinner_query_vars($vars) {
	$vars [] = 'wp_auto_spinner';
	return $vars;
}
add_filter ( 'query_vars', 'wp_auto_spinner_query_vars' );

/*
 * bulk pin ajax
 */
require_once 'asajax.php';

/*
 * LOG PAGE
 */
require_once 'as_log.php';

/*
 * spinner scheduler one post each 30 second
 */
require_once ('spinner_schedule.php');

/*
 * DB TABLES
 */

register_activation_hook ( __FILE__, 'create_table_wp_auto_spinner' );
require_once 'tables.php';

/*
 * custom coulmn spin status
 *
 */

/*
 * $wp_spinner_types = get_option('wp_spinner_types',array('post','product') );
 *
 * foreach ($wp_spinner_types as $type){
 * add_filter('manage_'.$type.'_posts_columns' , 'wp_auto_spinner_posts_columns');
 * }
 *
 *
 * add_action("manage_posts_custom_column", "wp_auto_spinner_columns_display");
 *
 * //add field function
 * function wp_auto_spinner_posts_columns($columns){
 *
 * return array_merge($columns,
 * array('Spin_Status' => 'Spin<br>Status' ));
 *
 * }
 *
 * //display field
 * function wp_auto_spinner_columns_display($coulmn){
 * if($coulmn == 'Spin_Status'){
 * global $post;
 * $post_id=$post->ID;
 *
 * //check if scheduled
 * $sched=get_post_meta($post_id, 'wp_auto_spinner_scheduled', true);
 *
 * if(trim($sched) != ''){
 * echo 'Scheduled';
 * }else{
 *
 * //not scheduled check if spinned
 * $spinned_cnt=get_post_meta($post_id, 'spinned_cnt', true);
 *
 * if( !empty($spinned_cnt) ){
 *
 * echo 'Spinnned';
 *
 * }else{
 * echo '--';
 * }
 *
 * }
 *
 * }
 * }
 *
 */

// nospin shortcode skip
function wp_auto_spinner_nospin_shortcode($atts, $content = null) {
	return $content;
}
add_shortcode ( 'nospin', 'wp_auto_spinner_nospin_shortcode' );

/*
 * deandev widget
 */
require_once 'widget.php';

/*
 * update
 */
require_once 'updated.php';

/*
 * rating
 */
require_once ('rating.php');

/*
 * License
 */
require_once 'aslicense.php';

/*
 * Ajax requests
 */
require_once 'pajax.php';

/**
 * custom sort by length function to sort html founds
 * 
 * @param unknown $a
 * @param unknown $b
 * @return number
 */
function wp_auto_spinner_sort_by_length($a, $b) {
	return strlen ( $b ) - strlen ( $a );
}
 
/**
 * Functions to convert seconds to human readable format
 * 
 */
function wp_auto_spinner_seconds_to_human_format($seconds){	
		$years = floor( $seconds / ( 365 * 24 * 60 * 60 ) );
		$months = floor( ( $seconds - $years * 365 * 24 * 60 * 60 ) / ( 30 * 24 * 60 * 60 ) );
		$weeks = floor( ( $seconds - $years * 365 * 24 * 60 * 60 - $months * 30 * 24 * 60 * 60 ) / ( 7 * 24 * 60 * 60 ) );
		$days = floor( ( $seconds - $years * 365 * 24 * 60 * 60 - $months * 30 * 24 * 60 * 60 - $weeks * 7 * 24 * 60 * 60 ) / ( 24 * 60 * 60 ) );
		$hours = floor( ( $seconds - $years * 365 * 24 * 60 * 60 - $months * 30 * 24 * 60 * 60 - $weeks * 7 * 24 * 60 * 60 - $days * 24 * 60 * 60 ) / ( 60 * 60 ) );
		$minutes = floor( ( $seconds - $years * 365 * 24 * 60 * 60 - $months * 30 * 24 * 60 * 60 - $weeks * 7 * 24 * 60 * 60 - $days * 24 * 60 * 60 - $hours * 60 * 60 ) / 60 );
		$seconds = $seconds % 60;
	
		$result = '';
		if ( $years > 0 ) {
			$result .= $years . ' years ';
			return $result;
		}
		if ( $months > 0 ) {
			$result .= $months . ' months ';
			return $result;
		}
		if ( $weeks > 0 ) {
			$result .= $weeks . ' weeks ';
			return $result;
		}
		if ( $days > 0 ) {
			$result .= $days . ' days ';
			return $result;
		}
		if ( $hours > 0 ) {
			$result .= $hours . ' hours ';
			return $result;
		}
		if ( $minutes > 0 ) {
			$result .= $minutes . ' minutes ';
			return $result;
		}
		if ( $seconds > 0 ) {
			$result .= $seconds . ' seconds ';
			return $result;
		}
	
		return trim( $result );
}

/**
 * Function to split a text to chunks of $char_count chars
 * It takes care of HTML so no chunk will contain broken HTML
 */
function wp_auto_spinner_split_text($article, $char_count)
{

    $chunks = array();
    $remeaning_text = $article;
	$mbstring_is_installed = true;

	//check if function mb_substr not exists and if it is not, log that and ask the user to install mbstring module
	if (!function_exists('mb_substr')) {
		wp_auto_spinner_log_new('WARNING!!!!', 'mbstring module is not installed on your server. Please install it to be able to use the plugin.');
		$mbstring_is_installed = false;
	}

	//if the $article is less than $char_count, return it as a single chunk
	if($mbstring_is_installed){
		$article_length = mb_strlen($article);
	}else{
		$article_length = strlen($article);
	}

	if ($article_length <= $char_count) {
		$chunks[] = $article;
		return $chunks;
	}

    while ($remeaning_text != "") {

        //get a chunk
        if($mbstring_is_installed){
			$chunk = mb_substr($remeaning_text, 0, $char_count); 
		}else{
			$chunk = substr($remeaning_text, 0, $char_count);
		}

        //remaining text
		if($mbstring_is_installed){
	        $remeaning_text = mb_substr($remeaning_text, $char_count);
		}else{
			$remeaning_text = substr($remeaning_text, $char_count);
		}

        //preg match <[^>]*$
        preg_match("{<[^>]*$}s", $chunk, $matches);

        
		//unclosed tag
		$found_unclosed_tag = '';
		if ( isset($matches[0]) ) $found_unclosed_tag = $matches[0];

        //if not empty, remove it from the chunk and add it to the remeaning text
        if ($found_unclosed_tag != "") {

            //remove found_unclosed_tag from the chunk using str_replace
            $chunk = preg_replace("{<[^>]*$}s", "", $chunk);

            //add the found_unclosed_tag to the remeaning text
            $remeaning_text = $found_unclosed_tag . $remeaning_text;

        }else{
            //check if a word was truncated between the chunk and the remeaning text
            //if the last charachter of the chunk is not a space and the first char of the remaining text then a word was truncated
            //to correct that case we should take the first word of the remaining text and add it to the chunk
            if ( $remeaning_text != " " && preg_match("{^[^ ]*}s", $remeaning_text) && preg_match("{[^ ]*$}s", $chunk) ) {

                //get the first word of the remaining text
                preg_match("{^[^ ]*}s", $remeaning_text, $matches);

                //add the first word of the remaining text to the chunk
                $chunk .= $matches[0];

                //remove the first word of the remaining text
                $remeaning_text = preg_replace("{^[^ ]*}s", "", $remeaning_text);

            }
        }
        $chunks[] = $chunk;

    }

	//if number of chunks is more than 1 and the last chunk is too small in size, we can merge it with the previous chunk
	//the chunk is regarded small if it is less than 30% of the char_count
	if(count($chunks) > 1){
		$last_chunk = $chunks[count($chunks) - 1];
		$last_chunk_size = strlen($last_chunk); 
		$min_chunk_size = $char_count * 0.3;

		if($last_chunk_size < $min_chunk_size){
			$chunks[count($chunks) - 2] .= $last_chunk;
			unset($chunks[count($chunks) - 1]);
		}
	}

    return $chunks;


}


//rotate and get a single item
function wp_auto_spinner_single_item($option_name){

	
	$option_value = get_option($option_name);
	
	
	//empty value
	if(trim($option_value) == '') return $option_value;
	
	$multiple_items = array_filter( explode("\n",  $option_value ) );
	
	 
	//single value
	if(count($multiple_items) == 1) return trim($multiple_items[0]);
	
	//multiple items, return first and send it to the last 
	if(count($multiple_items) > 0 ){
		
		$first_item = $multiple_items[0];
		
		unset($multiple_items[0]);
		
		$multiple_items[] = $first_item;
		
		 update_option($option_name , implode("\n" ,$multiple_items ));
		
		 return trim($first_item);
		
		
	}
	
	return trim($option_value);
	
}
 