HEX
Server: LiteSpeed
System: Linux ubuntu-8gb-hel1-1 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User: www (1000)
PHP: 8.3.24
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: /mnt/HC_Volume_101697859/livrariaboanoite.com.br/wp-content/plugins/woobase/admin/src/Rest/ACF.php
<?php
namespace VendBase\Rest;

// Prevent direct access to this file
defined("ABSPATH") || exit();

/**
 * Class ACF
 *
 * Creates new rest api to handle ACF requests
 */
class ACF
{
  /**
   * ACF constructor.
   */
  public function __construct()
  {
    add_action("rest_api_init", ["VendBase\Rest\ACF", "register_acf_field"]);
  }

  /**
   * Register a custom field to the product endpoint
   *
   * @return void
   */
  public static function register_acf_field()
  {
    foreach (["product", "shop_order", "product_cat", "shop_coupon", "shop_subscription"] as $type) {
      register_rest_field($type, "vendbase_acf", [
        "get_callback" => ["VendBase\Rest\ACF", "include_acf_fields_in_api_response"],
        "update_callback" => ["VendBase\Rest\ACF", "update_acf_fields"],
        "schema" => null,
      ]);
    }
  }

  /**
   * Adds ACF fields to the products response
   *
   * @param object $response
   * @param object $product
   * @param object $request
   *
   * @return $response
   */
  public static function include_acf_fields_in_api_response($object, $field_name, $request)
  {
    if (!current_user_can("manage_woocommerce") && !current_user_can("manage_options")) {
      return null;
    }

    if (!function_exists("get_field_objects")) {
      return null;
    }

    // Don't return ACF fields on list endpoints
    if ($request->get_param("id") === null) {
      return null;
    }

    // Determine if we're dealing with a post or a term
    $is_term = get_term($object["id"]);
    $object_id = $is_term ? $object["id"] : $request->get_param("id");

    if ($is_term && $is_term->name == $object["name"]) {
      $acf_object_type = "taxonomy";
      $acf_object_name = $is_term->taxonomy;
    } else {
      $post_type = get_post_type($object_id);
      $acf_object_type = "post_type";
      $acf_object_name = $post_type === "shop_order_placehold" ? "shop_order" : $post_type;
    }

    $field_groups = acf_get_field_groups([
      $acf_object_type => $acf_object_name,
    ]);

    $field_objects = self::get_all_acf_field_objects($object_id, $field_groups, $is_term);
    $groups_with_fields = [];

    foreach ($field_groups as $group) {
      $group_with_fields = [
        "name" => $group["title"],
        "id" => $group["ID"],
        "fields" => [],
      ];

      foreach ($field_objects as $field) {
        if ($field["parent"] == $group["ID"]) {
          $group_with_fields["fields"][] = $field;
        }
      }

      $groups_with_fields[] = $group_with_fields;
    }

    return $groups_with_fields;
  }

  /**
   * Retrieves all ACF field objects for a given object and field groups.
   *
   * @param int   $object_id    The ID of the object to get field values for.
   * @param array $field_groups An array of field group identifiers.
   * @param bool  $is_term      Whether the object is a term or not.
   * @return array An associative array of all fields.
   */
  private static function get_all_acf_field_objects($object_id, $field_groups, $is_term = false)
  {
    $all_fields = [];
    foreach ($field_groups as $field_group) {
      $fields = acf_get_fields($field_group);
      foreach ($fields as $field) {
        if ($is_term) {
          $field["value"] = get_field($field["name"], "term_" . $object_id);
        } else {
          $field["value"] = get_field($field["name"], $object_id);
        }
        $all_fields[$field["name"]] = $field;
      }
    }
    return $all_fields;
  }

  /**
   * Updates ACF fields for a WooCommerce product, including groups and repeaters.
   *
   * @param array           $fields    The array of fields to update.
   * @param WP_Post         $object    The WordPress post object.
   * @param string          $field_name The name of the field being updated.
   * @param WP_REST_Request $request   The current request object.
   * @param string          $post_type The post type of the object.
   *
   * @return bool|WP_Error True on success, WP_Error object on failure.
   */
  public static function update_acf_fields($fields, $object, $field_name, $request, $post_type)
  {
    // Check user capabilities
    if (!current_user_can("manage_woocommerce") && !current_user_can("manage_options")) {
      return new \WP_Error("rest_cannot_update", __("Sorry, you are not allowed to update this item."), ["status" => rest_authorization_required_code()]);
    }

    // Ensure ACF functions are available
    if (!function_exists("update_field")) {
      return new \WP_Error("acf_not_available", __("Advanced Custom Fields plugin is not active or available."), ["status" => 500]);
    }

    $updated = true;
    $is_term = false;
    if (taxonomy_exists($post_type)) {
      $is_term = true;
    }

    $object_id = $is_term ? $object->term_id : $object->get_id();

    foreach ($fields as $group) {
      foreach ($group["fields"] as $field) {
        $update_result = self::update_field_recursive($field, $object_id, $is_term);
        if ($update_result === false) {
          $updated = false;
        }
      }
    }

    if ($updated) {
      return true;
    } else {
      return new \WP_Error("acf_update_failed", __("Failed to update one or more ACF fields."), ["status" => 500]);
    }
  }

  /**
   * Recursively updates ACF fields, handling nested structures like groups and repeaters.
   *
   * @param array $field    The field to update.
   * @param int   $post_id  The ID of the post being updated.
   * @return bool True on success, false on failure.
   */
  private static function update_field_recursive($field, $object_id, $is_term)
  {
    $field_key = $field["key"];
    $field_value = $field["value"];

    // Handle different field types
    switch ($field["type"]) {
      case "group":
        foreach ($field_value as $sub_field_key => $sub_field_value) {
          $sub_field = acf_get_field($sub_field_key);
          if ($sub_field) {
            $sub_field["value"] = $sub_field_value;
            if (!self::update_field_recursive($sub_field, $object_id, $is_term)) {
              return false;
            }
          }
        }
        return true;

      case "repeater":
        if (!empty($field_value) && is_array($field_value)) {
          $prefix = $is_term ? "term_" : "";
          delete_field($field_key, $prefix . $object_id); // Clear existing repeater rows

          foreach ($field_value as $row_index => $row) {
            if ($is_term) {
              // For taxonomies, we need to update the entire repeater field
              $updated_value = get_field($field_key, $prefix . $object_id) ?: [];
              $updated_value[] = $row;
              if (!update_field($field_key, $updated_value, $prefix . $object_id)) {
                return false;
              }
            } else {
              // For post types, we can use update_row
              if (!update_row($field_key, $row_index + 1, $row, $object_id)) {
                return false;
              }
            }
          }
        }
        return true;

      default:
        return $is_term ? update_field($field_key, $field_value, "term_" . $object_id) : update_field($field_key, $field_value, $object_id);
    }
  }
}