Initial
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
node_modules
|
||||
132
api.php
Normal file
132
api.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
|
||||
function get_all_user_roles() {
|
||||
global $wp_roles;
|
||||
|
||||
if (!isset($wp_roles)) {
|
||||
$wp_roles = new WP_Roles();
|
||||
}
|
||||
|
||||
$roles = $wp_roles->roles;
|
||||
$role_names = [];
|
||||
|
||||
foreach ($roles as $role_key => $role_data) {
|
||||
$role_names[] = [
|
||||
'key' => $role_key,
|
||||
'name' => $role_data['name'],
|
||||
];
|
||||
}
|
||||
|
||||
return rest_ensure_response($role_names);
|
||||
}
|
||||
|
||||
function is_admin_user() {
|
||||
return true;
|
||||
/* return current_user_can('manage_options'); */
|
||||
}
|
||||
|
||||
function register_custom_user_roles_endpoint() {
|
||||
register_rest_route('lcp-paywall/v1', '/user-roles', [
|
||||
'methods' => 'GET',
|
||||
'callback' => 'get_all_user_roles',
|
||||
'permission_callback' => 'is_admin_user',
|
||||
]);
|
||||
}
|
||||
|
||||
add_action('rest_api_init', 'register_custom_user_roles_endpoint');
|
||||
|
||||
|
||||
/* GET TAXONOMIES */
|
||||
function get_taxonomies_by_post_type( $request ) {
|
||||
$post_type = $request->get_param('post_type');
|
||||
|
||||
if (empty($post_type)) {
|
||||
return new WP_Error('missing_post_type', 'Post type parameter is required', ['status' => 400]);
|
||||
}
|
||||
|
||||
// Get taxonomies associated with the post type
|
||||
$taxonomies = get_object_taxonomies($post_type, 'names'); // Use 'names' instead of 'objects' for simple list
|
||||
|
||||
// If no taxonomies found, return an error message
|
||||
if (empty($taxonomies)) {
|
||||
return new WP_Error('no_taxonomies', 'No taxonomies found for the given post type', ['status' => 404]);
|
||||
}
|
||||
|
||||
// Fetch taxonomy objects for the specific taxonomies
|
||||
$taxonomy_objects = [];
|
||||
foreach ($taxonomies as $taxonomy) {
|
||||
$taxonomy_objects[] = get_taxonomy($taxonomy); // Retrieve taxonomy object for each taxonomy
|
||||
}
|
||||
|
||||
return rest_ensure_response($taxonomy_objects);
|
||||
}
|
||||
|
||||
|
||||
function register_taxonomies_endpoint() {
|
||||
register_rest_route('lcp-paywall/v1', '/taxonomies', [
|
||||
'methods' => 'GET',
|
||||
'callback' => 'get_taxonomies_by_post_type',
|
||||
'args' => [
|
||||
'post_type' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
],
|
||||
],
|
||||
'permission_callback' => '__return_true',
|
||||
]);
|
||||
}
|
||||
|
||||
add_action('rest_api_init', 'register_taxonomies_endpoint');
|
||||
|
||||
function get_terms_by_taxonomy_slug( $request ) {
|
||||
// Get the taxonomy slug from the request parameters
|
||||
$taxonomy_slug = $request->get_param( 'taxonomy' );
|
||||
|
||||
// Check if the taxonomy slug is provided
|
||||
if ( empty( $taxonomy_slug ) ) {
|
||||
return new WP_Error( 'missing_taxonomy', 'Taxonomy slug parameter is required', array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
// Check if the taxonomy exists
|
||||
if ( ! taxonomy_exists( $taxonomy_slug ) ) {
|
||||
return new WP_Error( 'invalid_taxonomy', 'The provided taxonomy does not exist', array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Get the terms for the taxonomy
|
||||
$terms = get_terms( array(
|
||||
'taxonomy' => $taxonomy_slug,
|
||||
'hide_empty' => false, // Set to true to only get terms that have posts assigned
|
||||
) );
|
||||
|
||||
// Check if terms were found
|
||||
if ( is_wp_error( $terms ) ) {
|
||||
return $terms;
|
||||
}
|
||||
|
||||
if ( empty( $terms ) ) {
|
||||
return new WP_Error( 'no_terms', 'No terms found for the given taxonomy', array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Return the terms as a response
|
||||
return rest_ensure_response( $terms );
|
||||
}
|
||||
|
||||
function register_custom_taxonomy_terms_endpoint() {
|
||||
// Register the custom REST route
|
||||
register_rest_route( 'lcp-paywall/v1','/terms', array(
|
||||
'methods' => 'GET',
|
||||
'callback' => 'get_terms_by_taxonomy_slug',
|
||||
'args' => array(
|
||||
'taxonomy' => array(
|
||||
'required' => true,
|
||||
'validate_callback' => function( $param, $request, $key ) {
|
||||
// Validate that the taxonomy exists
|
||||
return taxonomy_exists( $param );
|
||||
},
|
||||
),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
add_action( 'rest_api_init', 'register_custom_taxonomy_terms_endpoint' );
|
||||
1
build/index.asset.php
Normal file
1
build/index.asset.php
Normal file
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'wp-components', 'wp-element'), 'version' => '33ab959b55f1e87d13f0');
|
||||
1
build/index.js
Normal file
1
build/index.js
Normal file
File diff suppressed because one or more lines are too long
149
lcp-paywall.php
Normal file
149
lcp-paywall.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
Plugin Name: LCP Paywall
|
||||
Plugin URI: https://localcontentpro.com/paywall
|
||||
Description: Flexible and customizable paywall solution for WordPress.
|
||||
Author: Local Content Pro
|
||||
Version: 0.0.1
|
||||
Author URI: https://localcontentpro.com/
|
||||
Tags: paywall, subscriptions, metered, membership, pay wall, content monetization, metered access, metered pay wall, paid content
|
||||
Text Domain: lcp
|
||||
*/
|
||||
|
||||
|
||||
// If this file is called directly, abort.
|
||||
if (!defined('WPINC')) {
|
||||
die;
|
||||
}
|
||||
|
||||
require_once plugin_dir_path(__FILE__) . 'api.php';
|
||||
// Add menu page to the admin dashboard
|
||||
add_action('admin_menu', 'lcp_paywall_add_admin_menu');
|
||||
add_action('admin_enqueue_scripts', 'lcp_paywall_enqueue_admin_scripts');
|
||||
|
||||
function lcp_paywall_add_admin_menu() {
|
||||
add_menu_page(
|
||||
'LCP Paywall', // Page title
|
||||
'LCP Paywall', // Menu title
|
||||
'manage_options', // Capability required
|
||||
'lcp-paywall', // Menu slug
|
||||
'lcp_paywall_admin_page', // Function to output content
|
||||
'dashicons-lock', // Icon (lock icon)
|
||||
30 // Position in menu
|
||||
);
|
||||
}
|
||||
|
||||
function lcp_paywall_admin_page() {
|
||||
// Check user capabilities
|
||||
if (!current_user_can('manage_options')) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
<div id="lcp-paywall-app-container">
|
||||
<!-- React app will render here -->
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function lcp_paywall_enqueue_admin_scripts($hook) {
|
||||
// Only load on our admin page
|
||||
if ('toplevel_page_lcp-paywall' !== $hook) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue the built js file
|
||||
wp_enqueue_script(
|
||||
'lcp-paywall-admin',
|
||||
plugins_url('build/index.js', __FILE__),
|
||||
['wp-element', 'wp-components'], // Added wp-components dependency
|
||||
filemtime(plugin_dir_path(__FILE__) . 'build/index.js'),
|
||||
true
|
||||
);
|
||||
|
||||
// Enqueue WordPress components styles
|
||||
wp_enqueue_style('wp-components');
|
||||
|
||||
// Get all registered post types
|
||||
$post_types = get_post_types(['public' => true], 'objects');
|
||||
$post_types_data = [];
|
||||
|
||||
foreach ($post_types as $post_type) {
|
||||
$post_types_data[] = [
|
||||
'name' => $post_type->name,
|
||||
'label' => $post_type->label,
|
||||
'singular_label' => $post_type->labels->singular_name
|
||||
];
|
||||
}
|
||||
|
||||
// Pass data to JavaScript
|
||||
wp_localize_script(
|
||||
'lcp-paywall-admin',
|
||||
'lcpPaywallData',
|
||||
[
|
||||
'postTypes' => $post_types_data,
|
||||
'nonce' => wp_create_nonce('lcp_paywall_nonce'),
|
||||
'ajaxUrl' => admin_url('admin-ajax.php')
|
||||
]
|
||||
);
|
||||
|
||||
// Add some basic styles
|
||||
wp_add_inline_style(
|
||||
'wp-admin',
|
||||
'
|
||||
.lcp-paywall-post-type {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
}
|
||||
.lcp-paywall-post-type.is-over {
|
||||
background: #f0f0f1;
|
||||
}
|
||||
.lcp-paywall-draggable-item {
|
||||
padding: 15px;
|
||||
margin: 5px 0;
|
||||
background: #f8f9fa;
|
||||
border: 1px dashed #ccd0d4;
|
||||
cursor: move;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
.lcp-paywall-draggable-item:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
}
|
||||
.lcp-paywall-draggable-item.is-dragging {
|
||||
opacity: 0.5;
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.lcp-paywall-rule-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.lcp-paywall-rule-controls .components-select-control {
|
||||
margin-bottom: 0;
|
||||
min-width: 120px;
|
||||
}
|
||||
.lcp-paywall-rule-controls .components-select-control__input {
|
||||
height: 36px;
|
||||
}
|
||||
.lcp-paywall-add-rule {
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #f0f0f1;
|
||||
}
|
||||
.lcp-paywall-add-rule-button.is-secondary {
|
||||
margin-left: 0;
|
||||
}
|
||||
.lcp-paywall-rules-container {
|
||||
min-height: 50px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
'
|
||||
);
|
||||
}
|
||||
19903
package-lock.json
generated
Normal file
19903
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "lcp-paywall",
|
||||
"version": "1.0.0",
|
||||
"description": "LCP Paywall WordPress Plugin",
|
||||
"scripts": {
|
||||
"build": "wp-scripts build",
|
||||
"start": "wp-scripts start",
|
||||
"check-engines": "wp-scripts check-engines"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wordpress/scripts": "^26.0.0",
|
||||
"@wordpress/components": "^25.0.0",
|
||||
"@wordpress/element": "^5.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1"
|
||||
}
|
||||
}
|
||||
237
src/components/DraggableItem.js
Normal file
237
src/components/DraggableItem.js
Normal file
@ -0,0 +1,237 @@
|
||||
import { useDrag, useDrop } from 'react-dnd';
|
||||
import { DateTimePicker,SelectControl, TextControl, __experimentalNumberControl as NumberControl } from '@wordpress/components';
|
||||
import { useState, useEffect, useCallback } from '@wordpress/element';
|
||||
|
||||
const DraggableItem = ({ id, index, moveItem, postType, children }) => {
|
||||
// Drag-and-drop hooks with memoization
|
||||
const [{ isDragging }, drag] = useDrag(
|
||||
useCallback(() => ({
|
||||
type: 'rule',
|
||||
item: { id, index },
|
||||
collect: (monitor) => ({
|
||||
isDragging: !!monitor.isDragging(),
|
||||
}),
|
||||
}), [id, index])
|
||||
);
|
||||
|
||||
const [, drop] = useDrop(
|
||||
useCallback(() => ({
|
||||
accept: 'rule',
|
||||
hover: (item) => {
|
||||
if (item.index !== index) {
|
||||
moveItem(item.index, index);
|
||||
item.index = index; // Keep track of the moved index
|
||||
}
|
||||
},
|
||||
}), [index, moveItem])
|
||||
);
|
||||
|
||||
// State management
|
||||
const [ruleType, setRuleType] = useState('post');
|
||||
const [lockType, setLockType] = useState('has_subscription');
|
||||
const [operator, setOperator] = useState('=');
|
||||
const [metaKey, setMetaKey] = useState('');
|
||||
const [roles, setRoles] = useState([]); // State to store user roles
|
||||
const [taxonomies, setTaxonomies] = useState([]); // State to store taxonomies
|
||||
const [terms, setTerms] = useState([]); // State to store terms of a selected taxonomy
|
||||
const [postContentLengthAmount, setPostContentLengthAmount] = useState(0);
|
||||
const [postContentLengthUnit, setPostContentLengthUnit] = useState('characters');
|
||||
const [postContentLengthOperator, setPostContentLengthOperator] = useState('=');
|
||||
const [postDate,setPostDate] = useState('')
|
||||
const [postDateOperator, setPostDateOperator] = useState('=');
|
||||
const [metaKeyOperator, setMetaKeyOperator] = useState('=');
|
||||
const [metaValue, setMetaValue] = useState('');
|
||||
|
||||
|
||||
// Fetch user roles from the WordPress REST API
|
||||
useEffect(() => {
|
||||
if (lockType === 'has_role') {
|
||||
fetch('/localcontentpro/wp-json/lcp-paywall/v1/user-roles') // Your custom REST API endpoint
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setRoles(data.map(role => ({ label: role.name, value: role.key })));
|
||||
})
|
||||
.catch((error) => console.error('Error fetching roles:', error));
|
||||
}
|
||||
}, [lockType]); // Fetch only when lockType is 'has_role'
|
||||
|
||||
// Fetch taxonomies for the current post type
|
||||
useEffect(() => {
|
||||
if ((lockType === 'in_term' || lockType === 'not_in_term') && postType) {
|
||||
fetch(`/localcontentpro/wp-json/lcp-paywall/v1/taxonomies?post_type=${postType}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const taxonomyOptions = Object.keys(data).map(taxonomy => ({
|
||||
label: data[taxonomy].name,
|
||||
value: taxonomy,
|
||||
}));
|
||||
setTaxonomies(taxonomyOptions);
|
||||
})
|
||||
.catch(error => console.error('Error fetching taxonomies:', error));
|
||||
}
|
||||
}, [lockType, postType]); // Fetch taxonomies when lockType is 'in_term' and postType changes
|
||||
|
||||
// Fetch terms when lockType is in_term or not_in_term and a taxonomy is selected
|
||||
useEffect(() => {
|
||||
if ((lockType === 'in_term' || lockType === 'not_in_term') && metaKey) {
|
||||
fetch(`/localcontentpro/wp-json/lcp-paywall/v1/terms?taxonomy=${metaKey}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const termOptions = data.map(term => ({
|
||||
label: term.name,
|
||||
value: term.id,
|
||||
}));
|
||||
setTerms(termOptions);
|
||||
})
|
||||
.catch(error => console.error('Error fetching terms:', error));
|
||||
}
|
||||
}, [lockType, metaKey]); // Fetch terms when lockType is 'in_term' or 'not_in_term' and metaKey (taxonomy) is selected
|
||||
|
||||
const postLockTypeOptions = [
|
||||
{ value: 'post_content_length', label: 'Post Content Length' },
|
||||
{ value: 'post_in', label: 'Post In' },
|
||||
{value: 'post_not_in', label: 'Post Not In' },
|
||||
{ value: 'meta_value', label: 'Meta Value' },
|
||||
{ value: 'in_term', label: 'In Term' },
|
||||
{ value: 'not_in_term', label: 'Not In Term' },
|
||||
{ value: 'older_than', label: 'Older Than' },
|
||||
{ value: 'newer_than', label: 'Newer Than' },
|
||||
{ value: 'author_in', label: 'Author In' },
|
||||
{ value: 'author_not_in', label: 'Author Not In' },
|
||||
{ value: 'post_date', label: 'Post Date' }
|
||||
];
|
||||
|
||||
const userLockTypeOptions = [
|
||||
{ label: 'Has Subscription', value: 'has_subscription' },
|
||||
{ label: 'Is Logged In', value: 'is_logged_in' },
|
||||
{ label: 'Role In', value: 'role_in' },
|
||||
{ label: 'Role Not In', value: 'role_not_in' },
|
||||
{ label: 'Meta Value', value: 'meta_value' }
|
||||
];
|
||||
|
||||
const userDeviceLockTypeOptions = [
|
||||
{ label: 'Browser In', value: 'browser_in' },
|
||||
{ label: 'Browser Not In', value: 'browser_not_in' },
|
||||
{ label: 'Operating System In', value: 'os_in' },
|
||||
{ label: 'Operating System Not In', value: 'os_not_in' }
|
||||
];
|
||||
|
||||
const comparisonOperators = [
|
||||
{ label: '=', value: '=' },
|
||||
{ label: '!=', value: '!=' },
|
||||
{ label: '>', value: '>' },
|
||||
{ label: '<', value: '<' },
|
||||
{ label: '>=', value: '>=' },
|
||||
{ label: '<=', value: '<=' },
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={(node) => drag(drop(node))}
|
||||
className={`lcp-paywall-draggable-item ${isDragging ? 'is-dragging' : ''}`}
|
||||
style={{ opacity: isDragging ? 0.5 : 1 }}
|
||||
>
|
||||
<div className="lcp-paywall-rule-controls">
|
||||
<SelectControl
|
||||
value={ruleType}
|
||||
options={[
|
||||
{ label: 'Current Post', value: 'post' },
|
||||
{ label: 'Current User', value: 'user' },
|
||||
{ label: 'Current User Device', value: 'user_device' },
|
||||
]}
|
||||
onChange={setRuleType}
|
||||
/>
|
||||
|
||||
<SelectControl
|
||||
value={lockType}
|
||||
options={
|
||||
ruleType === 'post' ? postLockTypeOptions : ruleType === 'user' ? userLockTypeOptions : userDeviceLockTypeOptions
|
||||
}
|
||||
onChange={setLockType}
|
||||
/>
|
||||
|
||||
{lockType === 'meta_value' && (
|
||||
<>
|
||||
<TextControl
|
||||
value={metaKey}
|
||||
onChange={setMetaKey}
|
||||
placeholder="Meta Key"
|
||||
/>
|
||||
<SelectControl
|
||||
value={metaKeyOperator}
|
||||
options={comparisonOperators}
|
||||
onChange={setMetaKeyOperator}
|
||||
/>
|
||||
|
||||
|
||||
<TextControl
|
||||
value={metaValue}
|
||||
onChange={setMetaValue}
|
||||
placeholder="Meta Value"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{lockType === 'has_role' && (
|
||||
<SelectControl
|
||||
value={metaKey}
|
||||
options={roles}
|
||||
onChange={setMetaKey}
|
||||
/>
|
||||
)}
|
||||
|
||||
{(lockType === 'in_term' || lockType === 'not_in_term') && (
|
||||
<>
|
||||
<SelectControl
|
||||
value={metaKey}
|
||||
options={taxonomies}
|
||||
onChange={setMetaKey}
|
||||
/>
|
||||
<SelectControl
|
||||
value={metaKey}
|
||||
options={terms}
|
||||
onChange={setMetaKey}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{lockType === 'post_content_length' && (
|
||||
<>
|
||||
<SelectControl
|
||||
value={postContentLengthOperator}
|
||||
options={comparisonOperators}
|
||||
onChange={setPostContentLengthOperator}
|
||||
/>
|
||||
<NumberControl
|
||||
value={postContentLengthAmount}
|
||||
onChange={setPostContentLengthAmount}
|
||||
/>
|
||||
<SelectControl
|
||||
value={postContentLengthUnit}
|
||||
options={[
|
||||
{ label: 'Characters', value: 'characters' },
|
||||
{ label: 'Words', value: 'words' } ]}
|
||||
onChange={setPostContentLengthUnit}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{lockType === 'post_date' && (
|
||||
<>
|
||||
<SelectControl
|
||||
value={postDateOperator}
|
||||
options={comparisonOperators}
|
||||
onChange={setPostDateOperator}
|
||||
/>
|
||||
<DateTimePicker
|
||||
value={postDate}
|
||||
onChange={setPostDate}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DraggableItem;
|
||||
120
src/components/PostTypeContainer.js
Normal file
120
src/components/PostTypeContainer.js
Normal file
@ -0,0 +1,120 @@
|
||||
import { useDrop } from 'react-dnd';
|
||||
import { Button, ToggleControl, __experimentalNumberControl as NumberControl, SelectControl } from '@wordpress/components';
|
||||
import { useState, useEffect, useCallback } from '@wordpress/element';
|
||||
import DraggableItem from './DraggableItem';
|
||||
|
||||
const PostTypeContainer = ({ postType }) => {
|
||||
const [rules, setRules] = useState([{ id: Date.now() }]);
|
||||
const [lockDefault, setLockDefault] = useState(false);
|
||||
const [enableMeter, setEnableMeter] = useState(false);
|
||||
const [meterAmount, setMeterAmount] = useState(0);
|
||||
const [meterDuration, setMeterDuration] = useState(1);
|
||||
const [meterCookieUnits, setMeterCookieUnits] = useState('hour');
|
||||
const [totalSeconds, setTotalSeconds] = useState(3600);
|
||||
|
||||
const [{ isOver }, drop] = useDrop(() => ({
|
||||
accept: 'rule',
|
||||
drop: () => ({ postType: postType.name }),
|
||||
collect: (monitor) => ({
|
||||
isOver: !!monitor.isOver(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const moveItem = useCallback((dragIndex, hoverIndex) => {
|
||||
setRules((prevRules) => {
|
||||
const newRules = [...prevRules];
|
||||
const dragItem = newRules[dragIndex];
|
||||
|
||||
// Remove the dragged item
|
||||
newRules.splice(dragIndex, 1);
|
||||
// Insert it at the new position
|
||||
newRules.splice(hoverIndex, 0, dragItem);
|
||||
|
||||
return newRules;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const addRule = () => {
|
||||
setRules([...rules, { id: Date.now() }]);
|
||||
};
|
||||
|
||||
const calculateTotalSeconds = (duration, unit) => {
|
||||
const unitToSeconds = {
|
||||
second: 1,
|
||||
minute: 60,
|
||||
hour: 3600,
|
||||
day: 86400,
|
||||
week: 604800,
|
||||
};
|
||||
return duration * (unitToSeconds[unit] || 0);
|
||||
};
|
||||
|
||||
// Update total seconds whenever duration or unit changes
|
||||
useEffect(() => {
|
||||
setTotalSeconds(calculateTotalSeconds(meterDuration, meterCookieUnits));
|
||||
}, [meterDuration, meterCookieUnits]);
|
||||
|
||||
return (
|
||||
<div className={`lcp-paywall-post-type ${isOver ? 'is-over' : ''}`} ref={drop}>
|
||||
<h3>{postType.label}</h3>
|
||||
<ToggleControl
|
||||
label="Lock Posts By Default"
|
||||
checked={lockDefault}
|
||||
onChange={setLockDefault}
|
||||
/>
|
||||
<ToggleControl
|
||||
label="Enable Meter"
|
||||
checked={enableMeter}
|
||||
onChange={setEnableMeter}
|
||||
/>
|
||||
{enableMeter && (
|
||||
<>
|
||||
<NumberControl
|
||||
label="Meter Amount"
|
||||
value={meterAmount}
|
||||
onChange={setMeterAmount}
|
||||
/>
|
||||
<NumberControl
|
||||
label="Meter Cookie Duration"
|
||||
value={meterDuration}
|
||||
onChange={setMeterDuration}
|
||||
/>
|
||||
<SelectControl
|
||||
label="Meter Cookie Units"
|
||||
value={meterCookieUnits}
|
||||
options={[
|
||||
{ label: 'Minutes', value: 'minute' },
|
||||
{ label: 'Hours', value: 'hour' },
|
||||
{ label: 'Days', value: 'day' },
|
||||
{ label: 'Weeks', value: 'week' },
|
||||
]}
|
||||
onChange={setMeterCookieUnits}
|
||||
/>
|
||||
<p><strong>Total Seconds:</strong> {totalSeconds}</p>
|
||||
</>
|
||||
)}
|
||||
<div className="lcp-paywall-rules-container">
|
||||
{rules.map((rule, index) => (
|
||||
<DraggableItem
|
||||
key={rule.id}
|
||||
id={rule.id}
|
||||
index={index}
|
||||
moveItem={moveItem}
|
||||
postType={postType.name}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="lcp-paywall-add-rule">
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={addRule}
|
||||
className="lcp-paywall-add-rule-button"
|
||||
>
|
||||
Add Rule
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostTypeContainer;
|
||||
24
src/index.js
Normal file
24
src/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { render } from '@wordpress/element';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import PostTypeContainer from './components/PostTypeContainer';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<div id="lcp-paywall-app">
|
||||
{window.lcpPaywallData.postTypes.map(postType => (
|
||||
<PostTypeContainer key={postType.name} postType={postType} />
|
||||
))}
|
||||
</div>
|
||||
</DndProvider>
|
||||
);
|
||||
};
|
||||
|
||||
// Wait for DOM to be ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const container = document.getElementById('lcp-paywall-app-container');
|
||||
if (container) {
|
||||
render(<App />, container);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user