11 Commits

Author SHA1 Message Date
94329dc91a Merge pull request 'Fix: Release not creating Zip file created' (#9) from feature-single-product into main
All checks were successful
Create Release / build (push) Successful in 3s
Reviewed-on: #9
2025-05-20 21:41:37 +00:00
ca3275fb4b Merge branch 'main' into feature-single-product 2025-05-20 14:38:37 -07:00
609883fc7f resolving issue with release not having rsync 2025-05-20 14:37:42 -07:00
60d5060398 Merge pull request 'Update automation to fix folder mess with updates and notes' (#8) from feature-single-product into main
Some checks failed
Create Release / build (push) Failing after 2s
Reviewed-on: #8
2025-05-20 21:34:21 +00:00
49703fd66d Merge branch 'main' into feature-single-product 2025-05-20 21:33:45 +00:00
9e1d8b8684 Update automation to fix folder mess with updates and notes 2025-05-20 14:29:59 -07:00
554e2ba93e Merge pull request 'Adding Feature Request for single product highlight' (#7) from feature-single-product into main
All checks were successful
Create Release / build (push) Successful in 3s
Reviewed-on: #7
2025-05-18 17:27:06 +00:00
1955b14ac5 Adding Feature Request for single product highlight 2025-05-18 10:25:53 -07:00
10634e8f7e Merge pull request 'Remove Debug Code for version' (#5) from fix-debug-notice into main
All checks were successful
Create Release / build (push) Successful in 3s
Reviewed-on: #5
2025-04-22 20:47:06 +00:00
e94ef7b84b Remove Debug Code for version 2025-04-22 13:46:42 -07:00
db1d5f8945 Merge pull request 'Major Update to add auto-update features' (#4) from auto-update into main
All checks were successful
Create Release / build (push) Successful in 3s
Reviewed-on: #4
2025-04-22 20:38:32 +00:00
6 changed files with 157 additions and 45 deletions

View File

@@ -25,7 +25,6 @@ jobs:
echo "version=$(date +'%Y.%m.%d-%H%M')" >> $GITHUB_OUTPUT
fi
# NEW STEP: Generate release notes from commits
- name: Generate release notes
id: release_notes
run: |
@@ -40,18 +39,11 @@ jobs:
COMMITS=$(git log --pretty=format:"* %s (%h)" ${LATEST_TAG}..HEAD --no-merges)
fi
# Escape newlines and special characters for GitHub Actions
COMMITS="${COMMITS//'%'/'%25'}"
COMMITS="${COMMITS//$'\n'/'%0A'}"
COMMITS="${COMMITS//$'\r'/'%0D'}"
# Create release notes with header
NOTES="## What's New in ${{ steps.get_version.outputs.version }}%0A%0A"
NOTES+="$COMMITS"
# Output to GitHub Actions
# Create release notes with header (without encoding newlines)
echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "$NOTES" >> $GITHUB_OUTPUT
echo "## What's New in ${{ steps.get_version.outputs.version }}" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Update plugin version
@@ -63,13 +55,24 @@ jobs:
- name: Create ZIP archive
run: |
zip -r fourthwall-store-embed.zip . -x ".git/*" ".gitea/*"
# Create a temp directory with the correct plugin folder name
mkdir -p /tmp/fourthwall-store-embed
# Copy files to the temp directory (excluding git and other unnecessary files)
cp -r * /tmp/fourthwall-store-embed/ 2>/dev/null || true
# Exclude .git and .gitea directories
rm -rf /tmp/fourthwall-store-embed/.git /tmp/fourthwall-store-embed/.gitea 2>/dev/null || true
# Create the ZIP file with the proper structure
cd /tmp
zip -r $GITHUB_WORKSPACE/fourthwall-store-embed.zip fourthwall-store-embed
- name: Create Release
uses: softprops/action-gh-release@v2
with:
token: "${{ secrets.REPO_TOKEN }}"
title: Fourthwall-store-embed Release ${{ steps.get_version.outputs.version }}
title: "Fourthwall-store-embed Release ${{ steps.get_version.outputs.version }}"
tag_name: ${{ steps.get_version.outputs.version }}
body: "${{ steps.release_notes.outputs.notes }}"
files: |

View File

@@ -35,8 +35,10 @@ jobs:
- name: Create plugin zip
run: |
mkdir -p build
zip -r build/fourthwall-store-embed.zip . -x ".git/*" ".gitea/*" "build/*" "*.git*"
mkdir -p /tmp/fourthwall-store-embed
rsync -av --exclude=".git" --exclude=".gitea" --exclude="build" . /tmp/fourthwall-store-embed/
cd /tmp
zip -r $GITEA_WORK_DIR/fourthwall-store-embed.zip fourthwall-store-embed
- name: Upload zip to release
uses: actions/upload-release-asset@v1

View File

@@ -1,12 +1,29 @@
# fourth-wall-embed-wp
A WordPress Plugin to embed a fourth wall embed.
A WordPress Plugin to embed a Fourthwall store or individual products.
### How to use the plugin
* Download the latest release from [releases](https://repo.anhonesthost.net/CyberCoveLLC/fourth-wall-embed-wp/releases)
* Upload the Plugin to WordPress
* In the WordPress Dashboard, Navigate to the Fourthwall settings page, and paste your store url.
* On the page you want have your store displayed, add the shortcode ```[fourthwall]```
* In the WordPress Dashboard, Navigate to the Fourthwall settings page, and paste your store URL.
This is an early release of the plugin, and if you can think of things that could be improved or find any bugs, please open an issue on the repository.
#### Display your entire store
To display your entire Fourthwall store on a page, use the shortcode:
```[fourthwall]```
#### Display a single product
To display an individual product from your Fourthwall store, use the shortcode with the product URL:
```[fourthwall_single url="https://your-store.fourthwall.com/products/product-name"]```
You can also display the product description by setting the `show_description` attribute to "true":
```[fourthwall_single url="https://your-store.fourthwall.com/products/product-name" show_description="true"]```
### Requirements
* WordPress 6.0 or higher
* PHP 7.4 or higher
* Active Fourthwall store
This plugin allows you to integrate your Fourthwall store directly into your WordPress site, either showing your complete product collection or featuring specific products individually.
If you can think of things that could be improved or find any bugs, please open an issue on the repository.

View File

@@ -1,7 +1,7 @@
<?php
/**
* Plugin Name: Fourthwall Store Embed
* Plugin URL: https://cybercove.io/
* Plugin URL: https://darksideofperfection.com/
* Description: Embed Fourthwall Store in WordPress
* Version: {auto_update_value_on_deploy}
* Author: Joshua Knapp

View File

@@ -48,11 +48,6 @@ function fwembed_check_for_updates() {
if ($response) {
$release_info = json_decode($response);
// Update debug info with latest version
$debug_data['latest_version'] = $release_info->tag_name ?? 'Not found';
$debug_data['response'] = substr(print_r($release_info, true), 0, 1000);
update_option('fwembed_update_debug', $debug_data);
// Get latest version from tag name
$latest_version = $release_info->tag_name;
@@ -96,8 +91,8 @@ function fwembed_check_for_updates() {
'package' => $download_url,
'icons' => [],
'banners' => [],
'tested' => '6.4.2',
'requires' => '5.0',
'tested' => '6.8',
'requires' => '6.2',
'compatibility' => new stdClass(),
];
@@ -108,23 +103,6 @@ function fwembed_check_for_updates() {
}
add_action('admin_init', 'fwembed_check_for_updates');
// Add admin notice for debugging
add_action('admin_notices', function() {
if (current_user_can('manage_options')) {
$debug = get_option('fwembed_update_debug', []);
echo '<div class="notice notice-info is-dismissible"><p>Update Debug: Current: ' .
esc_html($debug['current_version'] ?? 'N/A') . ', Latest: ' .
esc_html($debug['latest_version'] ?? 'N/A') . '</p>';
// Detailed debug info with query param
if (isset($_GET['fwembed_debug'])) {
echo '<pre>' . esc_html(print_r($debug, true)) . '</pre>';
}
echo '</div>';
}
});
// Add plugin information for the details popup/changelog
add_filter('plugins_api', function($result, $action, $args) {

View File

@@ -99,4 +99,116 @@ function fwembed_shortcode( $atts ) {
$store_render = '<div class="fw-store-parent">' . PHP_EOL . $store_html . PHP_EOL . '</div>';
return $store_render;
}
function fwembed_parse_html_single($url = null, $show_description = false) {
if ($url === null) {
throw new ValueError("Missing URL");
}
$ch = curl_init();
// More complete browser-like headers
$headers = [
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5',
'Connection: keep-alive',
'Upgrade-Insecure-Requests: 1',
'Cache-Control: max-age=0'
];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_ENCODING, "");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0');
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Only if necessary for testing
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt'); // Store cookies
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt'); // Use cookies
$html_content = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
return "Error fetching URL: " . $error;
}
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code == 403) {
curl_close($ch);
return "Access forbidden (403). The website may be blocking automated requests.";
}
curl_close($ch);
$html = null;
libxml_use_internal_errors(true);
$dom = new DOMDocument();
@$dom->loadHTML(loadHTML5($html_content), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->documentURI = $url;
$xpath = new DOMXPath($dom);
// Extract product information
$productTitle = $xpath->query('//h1[@class="product-info__title"]');
$productPrice = $xpath->query('//span[@class="product-info__price product-info__price--original"]');
$productImage = $xpath->query('//div[@data-gallery="gallery-slide"][1]//img[@class="gallery__image-object"]');
$productDesc = $xpath->query('//div[@class="product-info__description"]//div[@class="html-formatter"]');
if ($productTitle->length > 0 && $productImage->length > 0) {
$title = $productTitle->item(0)->textContent;
$price = $productPrice->length > 0 ? $productPrice->item(0)->textContent : '';
// Get image attributes
$imageNode = $productImage->item(0);
$imageSrc = $imageNode->getAttribute('src');
$imageAlt = $imageNode->getAttribute('alt');
// Build the HTML
$html = '<div class="product-tile">';
$html .= '<a class="product-link" target="_blank" href="' . $url . '">';
$html .= '<img class="tile__item tile__item--1" src="' . $imageSrc . '" alt="' . htmlspecialchars($imageAlt) . '">';
$html .= '<div class="tile__description">';
$html .= '<h3 class="tile__heading">' . htmlspecialchars(trim($title)) . '</h3>';
$html .= '<div class="tile__prices">';
$html .= '<span class="tile__price tile__price--original">' . trim($price) . '</span>';
$html .= '</div>';
$html .= '</div>';
$html .= '</a>';
// Add description if show_description is true
if ($show_description && $productDesc->length > 0) {
$description = $dom->saveHTML($productDesc->item(0));
$html .= '<div class="product-description">' . $description . '</div>';
}
$html .= '</div>';
}
libxml_clear_errors();
return $html;
}
function fwembed_single_shortcode($atts) {
$atts = shortcode_atts(
array(
'url' => '',
'show_description' => 'false',
),
$atts
);
if (empty($atts['url'])) {
return '<p>Error: URL is required for [fourthwall_single] shortcode</p>';
}
// Convert string 'true'/'false' to boolean
$show_description = filter_var($atts['show_description'], FILTER_VALIDATE_BOOLEAN);
$product_html = fwembed_parse_html_single($atts['url'], $show_description);
return '<div class="fw-single-product">' . PHP_EOL . $product_html . PHP_EOL . '</div>';
}
add_shortcode('fourthwall_single', 'fwembed_single_shortcode');
add_shortcode( 'fourthwall', 'fwembed_shortcode' );