HEX
Server: Apache
System: Linux WWW 6.1.0-40-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20) x86_64
User: web11 (1011)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/intranet.kauko.lt/wp-content/plugins/document-library-pro/src/Util/Util.php
<?php
namespace Barn2\Plugin\Document_Library_Pro\Util;

use Barn2\Plugin\Document_Library_Pro\Post_Type;
use Barn2\Plugin\Document_Library_Pro\Taxonomies;
use Barn2\Plugin\Document_Library_Pro\Util\Options;
use Barn2\Plugin\Document_Library_Pro\Dependencies\Lib\Util as Lib_Util;
use WP_Query;

defined( 'ABSPATH' ) || exit;

/**
 * Utilities
 *
 * @package   Barn2\document-library-pro
 * @author    Barn2 Plugins <support@barn2.com>
 * @license   GPL-3.0
 * @copyright Barn2 Media Ltd
 */
final class Util {

	/**
	 * Create a page and store the ID in an option. (adapted from WooCommerce)
	 *
	 * @param mixed  $slug Slug for the new page.
	 * @param string $option Option name to store the page's ID.
	 * @param string $page_title (default: '') Title for the new page.
	 * @param string $page_content (default: '') Content for the new page.
	 * @param int    $post_parent (default: 0) Parent for the new page.
	 * @return int page ID.
	 */
	public static function create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) {
		global $wpdb;

		$option_value = get_option( $option );

		if ( $option_value > 0 ) {
			$page_object = get_post( $option_value );

			if ( $page_object && 'page' === $page_object->post_type && ! in_array( $page_object->post_status, [ 'pending', 'trash', 'future', 'auto-draft' ], true ) ) {
				// Valid page is already in place.
				return $page_object->ID;
			}
		}

		if ( strlen( $page_content ) > 0 ) {
			// Search for an existing page with the specified page content (typically a shortcode).
			$shortcode        = str_replace( [ '<!-- wp:shortcode -->', '<!-- /wp:shortcode -->' ], '', $page_content );
			$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
		} else {
			// Search for an existing page with the specified page slug.
			$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' )  AND post_name = %s LIMIT 1;", $slug ) );
		}

		$valid_page_found = apply_filters( 'document_library_pro_create_page_id', $valid_page_found, $slug, $page_content );

		if ( $valid_page_found ) {
			if ( $option ) {
				update_option( $option, $valid_page_found );
			}
			return $valid_page_found;
		}

		// Search for a matching valid trashed page.
		if ( strlen( $page_content ) > 0 ) {
			// Search for an existing page with the specified page content (typically a shortcode).
			$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_content LIKE %s LIMIT 1;", "%{$page_content}%" ) );
		} else {
			// Search for an existing page with the specified page slug.
			$trashed_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status = 'trash' AND post_name = %s LIMIT 1;", $slug ) );
		}

		if ( $trashed_page_found ) {
			$page_id   = $trashed_page_found;
			$page_data = [
				'ID'          => $page_id,
				'post_status' => 'publish',
			];
			wp_update_post( $page_data );
		} else {
			$page_data = [
				'post_status'    => 'publish',
				'post_type'      => 'page',
				'post_author'    => 1,
				'post_name'      => $slug,
				'post_title'     => $page_title,
				'post_content'   => $page_content,
				'post_parent'    => $post_parent,
				'comment_status' => 'closed',
			];
			$page_id   = wp_insert_post( $page_data );
		}

		if ( $option ) {
			update_option( $option, $page_id );
		}

		return $page_id;
	}

	/**
	 * Round a number using the built-in `round` function, but unless the value to round is numeric
	 * (a number or a string that can be parsed as a number), apply 'floatval' first to it
	 * (so it will convert it to 0 in most cases).
	 *
	 * This is needed because in PHP 7 applying `round` to a non-numeric value returns 0,
	 * but in PHP 8 it throws an error. Specifically, in WooCommerce we have a few places where
	 * round('') is often executed.
	 *
	 * @param mixed $val The value to round.
	 * @param int   $precision The optional number of decimal digits to round to.
	 * @param int   $mode A constant to specify the mode in which rounding occurs.
	 *
	 * @return float The value rounded to the given precision as a float, or the supplied default value.
	 */
	public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ): float {
		if ( ! is_numeric( $val ) ) {
			$val = floatval( $val );
		}
		return round( $val, $precision, $mode );
	}

	/**
	 * Converts a string (e.g. 'yes' or 'no') to a bool.
	 *
	 * @param   string|bool $string String to convert. If a bool is passed it will be returned as-is.
	 * @return  bool
	 */
	public static function string_to_bool( $string ) {
		return is_bool( $string ) ? $string : ( 'yes' === strtolower( $string ) || 1 === $string || 'true' === strtolower( $string ) || '1' === $string );
	}

	/**
	 * Sanitize array recursively.
	 *
	 * @param mixed $array
	 * @return mixed
	 */
	public static function sanitize_array_recursive( $array ) {
		if ( is_array( $array ) ) {
			return array_map( self::class . '::sanitize_array_recursive', $array );
		} else {
			return is_scalar( $array ) ? sanitize_text_field( $array ) : $array;
		}
	}

	/**
	 * Associated attachment to post.
	 *
	 * @param mixed $attachment_id
	 * @param mixed $post_id
	 */
	public static function associate_attachment( $attachment_id, $post_id ) {
		global $wpdb;

		$wpdb->update(
			$wpdb->posts,
			[ 'post_parent' => $post_id ],
			[ 'ID' => $attachment_id ],
			[ '%d' ],
			[ '%d' ]
		);
	}

	/**
	 * Disassociate attachment to post.
	 *
	 * @param mixed $attachment_id
	 */
	public static function disassociate_attachment( $attachment_id ) {
		global $wpdb;

		$wpdb->update(
			$wpdb->posts,
			[ 'post_parent' => 0 ],
			[ 'ID' => $attachment_id ],
			[ '%d' ],
			[ '%d' ]
		);
	}

	/**
	 * Helper function to replace wp_localize_script
	 *
	 * @param string $script_handle
	 * @param string $variable_name
	 * @param array $script_params
	 */
	public static function add_inline_script_params( $script_handle, $variable_name, $script_params ) {
		$script_data = sprintf( 'var %1$s = %2$s', $variable_name, wp_json_encode( $script_params ) );
		wp_add_inline_script( $script_handle, $script_data, 'before' );
	}

	/**
	 * Determins if a string ends with another string
	 *
	 * @param string $haystack
	 * @param string $needle
	 * @return bool
	 */
	public static function str_ends_with( $haystack, $needle ) {
		$length = strlen( $needle );
		return $length > 0 ? substr( $haystack, -$length ) === $needle : true;
	}

	/**
	 * Retrieve a linked list of terms (for Author and File Types).
	 *
	 * @param \WP_Post $post
	 * @param string $taxonomy
	 * @param string $sep
	 * @return string
	 */
	public static function get_the_fake_linked_term_names( $post, $taxonomy, $sep = ', ' ) {
		$terms = get_the_terms( $post, $taxonomy );

		if ( ! $terms || ! is_array( $terms ) ) {
			return '';
		}

		$linked_terms = array_map(
			function ( $term ) {
				return sprintf( '<a href="#">%s</a>', $term->name );
			},
			$terms
		);

		return implode( $sep, $linked_terms );
	}

	/**
	 * Check if the Advanced Custom Fields plugin is active.
	 *
	 * @return bool
	 */
	public static function is_acf_active() {
		return class_exists( '\ACF' );
	}

	/**
	 * Check if the Easy Post Types plugin is active.
	 *
	 * @return bool
	 */
	public static function is_ept_active() {
		return class_exists( 'Barn2\Plugin\Easy_Post_Types_Fields\Util' );
	}

	/**
	 * Is expired document
	 *
	 * @param \WP_Post $post
	 * @return bool
	 */
	public static function is_expired_document( $post ) {
		if ( Post_Type::POST_TYPE_SLUG !== $post->post_type ) {
			return false;
		}

		$document = dlp_get_document( $post->ID );

		if ( $document && 'expired' !== $document->get_expiry_status() ) {
			return false;
		}

		return true;
	}

	/**
	 * Count expired posts
	 *
	 * @return int
	 */
	public static function count_expired_posts() {
		global $wpdb;

		$cache_key = 'dlp_expired_posts_count';

		$counts = wp_cache_get( $cache_key, 'counts' );

		$counts = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) AS total_expired_posts
				FROM {$wpdb->posts} p
				JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
				WHERE pm.meta_key = %s
				AND pm.meta_value < %d",
				'_dlp_expiry_timestamp',
				time()
			)
		);

		if ( null === $counts ) {
			$counts = 0;
		}

		wp_cache_set( $cache_key, $counts, 'counts' );

		return $counts;
	}

	/**
	 * Get the eligible documents for auto thumbnail
	 *
	 * @param int $batch_size
	 * @return array
	 */
	public static function get_eligible_auto_thumbnail_documents( $batch_size ) {
		$file_type_terms = [ 'jpg', 'jpeg', 'gif', 'png' ];

		if ( Media::has_pdf_previews() ) {
			$file_type_terms[] = 'pdf';
		}

		$args = [
			'post_type'              => Post_Type::POST_TYPE_SLUG,
			'post_status'            => 'any',
			'posts_per_page'         => $batch_size,
			'suppress_filters'       => false,
			'cache_results'          => false,
			'update_post_meta_cache' => false,
			'update_post_term_cache' => false,
			'meta_query'             => [
				'relation' => 'AND',
				[
					'key'     => '_thumbnail_id',
					'compare' => 'NOT EXISTS',
				],
				[
					'key'     => '_dlp_auto_thumbnail_processed',
					'compare' => 'NOT EXISTS',
				],
				[
					'key'     => '_dlp_document_link_type',
					'value'   => 'file',
					'compare' => '=',
				],
			],
			'tax_query'              => [
				[
					'taxonomy' => Taxonomies::FILE_TYPE_SLUG,
					'field'    => 'slug',
					'terms'    => $file_type_terms,
				],
			],
			'fields'                 => 'ids',
		];

		$query = new WP_Query( $args );

		return $query->posts;
	}

	/**
	 * Get a read more link with a space before it.
	 *
	 * @param string $path The relative path to the link (relative to barn2.com).
	 * @param bool $new_tab Whether to open the link in a new tab.
	 *
	 * @return string The read more link.
	 */
	public static function read_more_link( $path, $new_tab = true ): string {
		return sprintf( ' %s', Lib_Util::barn2_link( $path, __( 'Read more', 'document-library-pro' ), $new_tab ) );
	}

	/**
	 * Normalize user arguments provided to shortcode.
	 *
	 * @param array $args
	 * @return array
	 * @deprecated
	 */
	public static function normalize_user_arguments( $args ) {
		_deprecated_function( __METHOD__, '1.3', esc_html( Options::class . '::normalize_user_arguments' ) );
		return Options::normalize_user_arguments( $args );
	}

	/**
	 * Retrive the Document post type fields.
	 *
	 * @return array
	 * @deprecated
	 */
	public static function get_document_fields() {
		_deprecated_function( __METHOD__, '1.3', esc_html( Options::class . '::get_document_fields' ) );
		return Options::get_document_fields();
	}

	/**
	 * Retrieve the single document display option.
	 *
	 * @return array
	 * @deprecated
	 */
	public static function get_document_display_fields() {
		_deprecated_function( __METHOD__, '1.3', esc_html( Options::class . '::get_document_display_fields' ) );
		return Options::get_document_display_fields();
	}

	/**
	 * Delete table transients
	 *
	 * @return void
	 */
	public static function delete_table_transients() {
		global $wpdb;
		// Query to delete all wpt table caches
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s",
				'_transient_dlp_%_data',
				'_transient_timeout_dlp_%_data'
			)
		);
	}

	/**
	 * Get ACF custom fields.
	 *
	 * @param string $post_type
	 * @return array
	 */
	public static function get_acf_custom_fields( $post_type, $priority = 10 ) {
		$acf_fields = [];

		$allowed_cf_field_types = [
			'text',
			'textarea',
			'select',
		];

		$groups = acf_get_field_groups( [ 'post_type' => $post_type ] );

		foreach ( (array) $groups as $group ) {
			$fields = acf_get_fields( $group['key'] );
			foreach ( (array) $fields as $field ) {
				// Skip if custom field type is not allowed

				if ( ! in_array( $field['type'], $allowed_cf_field_types ) ) {
					continue;
				}

				$type = $field['type'] === 'wysiwyg' ? 'editor' : $field['type'];

				$field_data = [
					'name'        => $field['name'],
					'label'       => $field['label'],
					'required'    => $field['required'],
					'description' => $field['instructions'],
					'placeholder' => $field['placeholder'],
					'type'        => $type,
					'priority'    => $priority,
				];
				if ( $field['type'] === 'select' ) {
					$field_data['options'] = $field['choices'];
				}
				$acf_fields[ 'acf:' . $field['name'] ] = $field_data;

				++$priority;
			}
		}

		return $acf_fields;
	}

	/**
	 * Get Easy Post Types custom fields.
	 *
	 * @param string $post_type
	 * @return array
	 */
	public static function get_ept_custom_fields( $post_type, $priority = 11 ) {
		$ept_fields = [];

		$fields = \Barn2\Plugin\Easy_Post_Types_Fields\Util::get_custom_fields( $post_type );

		foreach ( (array) $fields as $field ) {
			$ept_fields[ 'ept:' . $field['slug'] ] = [
				'name'        => $field['slug'],
				'label'       => $field['name'],
				'required'    => false,
				'placeholder' => '',
				'type'        => $field['type'],
				'priority'    => $priority,
			];
			++$priority;
		}

		return $ept_fields;
	}
}