Changeset 3441218
- Timestamp:
- 01/16/2026 07:13:03 PM (3 months ago)
- Location:
- rss-to-post-generator
- Files:
-
- 8 edited
- 1 copied
-
tags/1.1.3 (copied) (copied from rss-to-post-generator/trunk)
-
tags/1.1.3/assets/js/admin.js (modified) (5 diffs)
-
tags/1.1.3/includes/class-admin.php (modified) (20 diffs)
-
tags/1.1.3/readme.txt (modified) (2 diffs)
-
tags/1.1.3/rss2post.php (modified) (2 diffs)
-
trunk/assets/js/admin.js (modified) (5 diffs)
-
trunk/includes/class-admin.php (modified) (20 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/rss2post.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
rss-to-post-generator/tags/1.1.3/assets/js/admin.js
r3415485 r3441218 606 606 }); 607 607 608 // Handler for article size selection 609 $('#article-size').on('change', function() { 610 const size = $(this).val(); 611 const $feedbackSpan = $('#article-size-save-feedback'); 612 613 $feedbackSpan.text('Saving...').removeClass('success error').addClass('saving'); 614 615 $.ajax({ 616 url: rss2post_ajax.ajax_url, 617 type: 'POST', 618 data: { 619 action: 'rss2post_save_article_size', 620 nonce: rss2post_ajax.nonce, 621 article_size: size 622 }, 623 success: function(response) { 624 if (response.success) { 625 $feedbackSpan.text('Saved!').removeClass('saving error').addClass('success'); 626 } else { 627 $feedbackSpan.text('Error: ' + (response.data.message || 'Could not save.')).removeClass('saving success').addClass('error'); 628 } 629 }, 630 error: function() { 631 $feedbackSpan.text('Error: AJAX request failed.').removeClass('saving success').addClass('error'); 632 }, 633 complete: function() { 634 setTimeout(function() { 635 $feedbackSpan.text('').removeClass('saving success error'); 636 }, 3000); 637 } 638 }); 639 }); 640 608 641 $('#save-tags-button').on('click', function() { 609 642 const selectedTags = []; … … 741 774 }); 742 775 776 $('#runs-per-day, #articles-per-day').on('input', function() { 777 let val = $(this).val(); 778 // Allow empty string to let user clear and retype 779 if (val === '') return; 780 781 // Remove any non-digit characters 782 val = val.replace(/[^0-9]/g, ''); 783 784 let num = parseInt(val); 785 if (isNaN(num)) num = ''; 786 else if (num < 1) num = 1; 787 else if (num > 10) num = 10; 788 789 // Update value if it changed (handle strings vs numbers carefully) 790 if (val !== '' && num !== parseInt($(this).val())) { 791 $(this).val(num); 792 } else if (val !== $(this).val()) { 793 // Covers the case where non-digits were removed 794 $(this).val(val); 795 } 796 }); 797 798 // Ensure valid value on blur 799 $('#runs-per-day, #articles-per-day').on('blur', function() { 800 let val = parseInt($(this).val()); 801 if (isNaN(val) || val < 1) { 802 $(this).val(1); 803 } else if (val > 10) { 804 $(this).val(10); 805 } 806 }); 807 808 $('#save-automated-settings-button').on('click', saveAutomatedSettings); 809 743 810 $('input[name="image_source"]').on('change', function() { 744 811 if ($(this).val() === 'pexels') { … … 898 965 // The more complete one defined earlier in the file will be used. 899 966 967 function saveAutomatedSettings() { 968 const runsPerDay = parseInt($('#runs-per-day').val()) || 2; 969 const articlesPerDay = parseInt($('#articles-per-day').val()) || 10; 970 971 if (runsPerDay < 1 || runsPerDay > 10) { 972 alert('Runs per day must be between 1 and 10.'); 973 return; 974 } 975 if (articlesPerDay < 1 || articlesPerDay > 10) { 976 alert('Articles per day must be between 1 and 10.'); 977 return; 978 } 979 980 const $button = $('#save-automated-settings-button'); 981 const $feedback = $('#save-automated-settings-feedback'); 982 983 $button.prop('disabled', true).text('Saving...'); 984 $feedback.text('Saving...').removeClass('success error').addClass('saving'); 985 986 $.ajax({ 987 url: rss2post_ajax.ajax_url, 988 type: 'POST', 989 data: { 990 action: 'rss2post_update_automated_settings', 991 nonce: rss2post_ajax.nonce, 992 runs_per_day: runsPerDay, 993 articles_per_day: articlesPerDay 994 }, 995 success: function(response) { 996 if (response.success) { 997 $feedback.text('Settings saved!').removeClass('saving error').addClass('success'); 998 } else { 999 $feedback.text('Error: ' + (response.data.message || 'Could not save.')).removeClass('saving success').addClass('error'); 1000 } 1001 }, 1002 error: function() { 1003 $feedback.text('Error: Failed to save settings.').removeClass('saving success').addClass('error'); 1004 }, 1005 complete: function() { 1006 $button.prop('disabled', false).text('Save Automation Settings'); 1007 setTimeout(function() { 1008 $feedback.text('').removeClass('saving success error'); 1009 }, 3000); 1010 } 1011 }); 1012 } 1013 900 1014 function toggleAutomatedPosting() { 901 1015 const isEnabled = $(this).is(':checked'); 902 1016 const feeds = $('#rss-feeds').val().trim(); 1017 const runsPerDay = parseInt($('#runs-per-day').val()) || 2; 1018 const articlesPerDay = parseInt($('#articles-per-day').val()) || 10; 903 1019 904 1020 if (userTier !== 'pro' && userTier !== 'lifetime' && isEnabled) { … … 911 1027 if (!feeds) { 912 1028 alert('Please enter at least one RSS feed URL in the "RSS Feed URLs" section before enabling automated posting.'); 1029 $(this).prop('checked', false); 1030 return; 1031 } 1032 if (articlesPerDay > 10) { 1033 alert('The maximum amount of generation + posts is 10 per day.'); 913 1034 $(this).prop('checked', false); 914 1035 return; … … 932 1053 enabled: isEnabled, 933 1054 feeds: feeds, 1055 runs_per_day: runsPerDay, 1056 articles_per_day: articlesPerDay, 934 1057 current_username: $('#wp-username').val().trim(), 935 1058 current_password: $('#wp-password').val().trim() -
rss-to-post-generator/tags/1.1.3/includes/class-admin.php
r3438847 r3441218 16 16 add_action('rss2post_automated_hourly_job', array($this, 'do_automated_posting_job')); // Retained in case it's a valid, albeit unused, hook for some users 17 17 add_action('rss2post_automated_12h_job', array($this, 'do_automated_posting_job')); 18 add_action('rss2post_automated_job', array($this, 'do_automated_posting_job')); 18 19 add_action('wp_ajax_rss2post_save_credentials', array($this, 'ajax_save_credentials')); 19 20 add_action('wp_ajax_rss2post_save_language', array($this, 'ajax_save_language')); 21 add_action('wp_ajax_rss2post_save_article_size', array($this, 'ajax_save_article_size')); 20 22 add_action('wp_ajax_rss2post_update_automated_feeds', array($this, 'ajax_update_automated_feeds')); 23 add_action('wp_ajax_rss2post_update_automated_settings', array($this, 'ajax_update_automated_settings')); 21 24 add_action('wp_ajax_rss2post_create_stripe_checkout', array($this, 'ajax_create_stripe_checkout')); 22 25 add_action('wp_ajax_rss2post_verify_payment', array($this, 'ajax_verify_payment_and_upgrade')); … … 30 33 add_action('wp_ajax_rss2post_save_api_keys', array($this, 'ajax_save_api_keys')); 31 34 add_action('rss2post_daily_subscription_check', array($this, 'check_all_pro_subscriptions')); 35 add_filter('cron_schedules', array($this, 'add_custom_cron_schedules')); 32 36 33 37 if (!wp_next_scheduled('rss2post_daily_subscription_check')) { 34 38 wp_schedule_event(time(), 'daily', 'rss2post_daily_subscription_check'); 35 39 } 40 } 41 42 public function add_custom_cron_schedules($schedules) { 43 $settings = get_option('rss2post_settings', array()); 44 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 45 if ($runs_per_day < 1) $runs_per_day = 1; 46 if ($runs_per_day > 10) $runs_per_day = 10; 47 48 $interval = 86400 / $runs_per_day; 49 50 $schedules['rss2post_custom_schedule'] = array( 51 'interval' => $interval, 52 'display' => "Every {$interval} seconds (RSS2Post Custom)" 53 ); 54 return $schedules; 36 55 } 37 56 … … 412 431 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 413 432 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 433 wp_clear_scheduled_hook('rss2post_automated_job'); 414 434 return; 415 435 } … … 419 439 return; 420 440 } 441 442 // --- New Distribution Logic Start --- 443 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 444 $articles_per_day = isset($settings['articles_per_day']) ? (int)$settings['articles_per_day'] : 10; 445 446 // Load daily stats 447 $daily_stats = get_option('rss2post_daily_stats', array( 448 'date' => '', 449 'runs_completed' => 0, 450 'articles_posted' => 0 451 )); 452 453 $current_date = current_time('Y-m-d'); 454 455 // Reset stats if new day 456 if ($daily_stats['date'] !== $current_date) { 457 RSS2Post::log("New day detected (Old: {$daily_stats['date']}, New: {$current_date}). Resetting daily stats.", 'info'); 458 $daily_stats = array( 459 'date' => $current_date, 460 'runs_completed' => 0, 461 'articles_posted' => 0 462 ); 463 } 464 465 // Check limits 466 if ($daily_stats['runs_completed'] >= $runs_per_day) { 467 RSS2Post::log("Daily run limit reached ({$daily_stats['runs_completed']}/{$runs_per_day}). Job exiting.", 'info'); 468 return; 469 } 470 471 if ($daily_stats['articles_posted'] >= $articles_per_day) { 472 RSS2Post::log("Daily article limit reached ({$daily_stats['articles_posted']}/{$articles_per_day}). Job exiting.", 'info'); 473 // We still increment runs_completed to keep the schedule "ticking" correctly relative to the day? 474 // Actually, if we skip because of article limit, we effectively consume a run slot without posting. 475 $daily_stats['runs_completed']++; 476 update_option('rss2post_daily_stats', $daily_stats); 477 return; 478 } 479 480 // Calculate articles for this run 481 $remaining_runs = $runs_per_day - $daily_stats['runs_completed']; 482 // Safety check to avoid division by zero (though runs_completed check above should prevent this) 483 if ($remaining_runs <= 0) $remaining_runs = 1; 484 485 $remaining_articles = $articles_per_day - $daily_stats['articles_posted']; 486 if ($remaining_articles < 0) $remaining_articles = 0; 487 488 // Distribute remaining articles over remaining runs (ceil ensures we don't under-post) 489 $articles_to_post_now = (int) ceil($remaining_articles / $remaining_runs); 490 491 RSS2Post::log("Run #{$daily_stats['runs_completed']} of {$runs_per_day}. Posted today: {$daily_stats['articles_posted']}/{$articles_per_day}. Planning to post {$articles_to_post_now} articles.", 'info'); 492 493 if ($articles_to_post_now <= 0) { 494 $daily_stats['runs_completed']++; 495 update_option('rss2post_daily_stats', $daily_stats); 496 return; 497 } 498 499 $max_articles_per_run = $articles_to_post_now; 500 // --- New Distribution Logic End --- 421 501 422 502 $automated_feeds = isset($settings['automated_rss_feeds']) && is_array($settings['automated_rss_feeds']) ? $settings['automated_rss_feeds'] : array(); … … 550 630 // Step 2: Round-robin distribution across feeds 551 631 $articles_to_post = array(); 552 $max_articles_per_run = 6; // Maximum total articles to post per run632 // $max_articles_per_run is set above based on daily distribution 553 633 $posted_count = 0; 554 634 $feed_indices = array(); … … 594 674 // Step 3: Post the selected articles and track which feeds successfully posted 595 675 $successfully_posted_by_feed = array(); // Track successful posts per feed 676 $actually_posted_count = 0; 596 677 597 678 foreach ($articles_to_post as $single_article_to_post) { … … 602 683 603 684 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 685 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 604 686 605 687 $data_for_api = array( … … 615 697 'available_tags' => $all_site_tags, 616 698 'content_language' => $content_language, 699 'article_size' => $article_size, 617 700 'automated_tag_assign' => isset($settings['automated_tag_assign']) ? (bool)$settings['automated_tag_assign'] : false, 618 701 'auto_category_assign' => $auto_category_assign, … … 658 741 } 659 742 $successfully_posted_by_feed[$feed_url_key][] = $single_article_to_post['original_guid']; 743 $actually_posted_count++; 660 744 } 661 745 } else { … … 665 749 wp_cache_delete('alloptions', 'options'); 666 750 } 751 752 // Update stats 753 $daily_stats['runs_completed']++; 754 $daily_stats['articles_posted'] += $actually_posted_count; 755 update_option('rss2post_daily_stats', $daily_stats); 756 RSS2Post::log("Stats updated. Runs: {$daily_stats['runs_completed']}, Articles posted today: {$daily_stats['articles_posted']}", 'info'); 667 757 668 758 // Step 4: Update last processed GUIDs ONLY for feeds that successfully posted articles … … 699 789 } 700 790 $new_status = isset($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === 'true'; 791 792 // Save frequency and articles settings if provided 793 if (isset($_POST['runs_per_day'])) { 794 $runs = (int) $_POST['runs_per_day']; 795 if ($runs < 1) $runs = 1; 796 if ($runs > 10) $runs = 10; 797 $settings['runs_per_day'] = $runs; 798 } 799 800 if (isset($_POST['articles_per_day'])) { 801 $articles = (int) $_POST['articles_per_day']; 802 if ($articles < 1) $articles = 1; 803 if ($articles > 10) $articles = 10; 804 $settings['articles_per_day'] = $articles; 805 } 701 806 702 807 // Always update feeds when toggling (both enabling and re-enabling) … … 771 876 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 772 877 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 878 wp_clear_scheduled_hook('rss2post_automated_job'); 773 879 774 880 RSS2Post::log('Running automated posting job immediately upon enabling.', 'info'); … … 780 886 } 781 887 782 RSS2Post::log('Attempting to schedule rss2post_automated_12h_job.', 'info'); 783 if (!wp_next_scheduled('rss2post_automated_12h_job')) { 784 RSS2Post::log('No existing rss2post_automated_12h_job found. Proceeding to schedule.', 'info'); 785 // Schedule the first run for a short time from now to make testing easier, then 'twicedaily' will take over. 786 // Or, use time() if the first run should be in 12 hours. 787 // For testing visibility, let's schedule it for 1 minute from now. 788 // $first_run_time = time() + 60; // For quick testing 789 // For production, it should align with 'twicedaily' logic, so time() is fine, WP handles the first run based on 'twicedaily'. 790 $scheduled = wp_schedule_event(time(), 'twicedaily', 'rss2post_automated_12h_job'); 888 RSS2Post::log('Attempting to schedule rss2post_automated_job.', 'info'); 889 if (!wp_next_scheduled('rss2post_automated_job')) { 890 $scheduled = wp_schedule_event(time(), 'rss2post_custom_schedule', 'rss2post_automated_job'); 791 891 if ($scheduled === false) { 792 RSS2Post::log('wp_schedule_event for rss2post_automated_ 12h_job FAILED.', 'error');892 RSS2Post::log('wp_schedule_event for rss2post_automated_job FAILED.', 'error'); 793 893 } else { 794 RSS2Post::log('wp_schedule_event for rss2post_automated_12h_job SUCCEEDED. Check cron tools.', 'info'); 795 } 796 } else { 797 RSS2Post::log('rss2post_automated_12h_job is already scheduled. Next run at timestamp: ' . wp_next_scheduled('rss2post_automated_12h_job'), 'info'); 894 RSS2Post::log('wp_schedule_event for rss2post_automated_job SUCCEEDED with rss2post_custom_schedule.', 'info'); 895 } 798 896 } 799 897 800 // Let's get the event details again after attempting to schedule 801 $event_after_schedule = wp_get_scheduled_event('rss2post_automated_12h_job'); 802 if ($event_after_schedule) { 803 RSS2Post::log('Verification with wp_get_scheduled_event for rss2post_automated_12h_job: Hook=' . $event_after_schedule->hook . ', Timestamp=' . $event_after_schedule->timestamp . ' (Next run: ' . get_date_from_gmt(gmdate('Y-m-d H:i:s', $event_after_schedule->timestamp), 'Y-m-d H:i:s') . '), Schedule=' . $event_after_schedule->schedule, 'info'); 804 } else { 805 RSS2Post::log('Verification with wp_get_scheduled_event for rss2post_automated_12h_job: No event found. This is unexpected if scheduling succeeded.', 'error'); 806 } 807 wp_send_json_success(array('message' => 'Automated posting enabled. Please check your WordPress cron events list and debug logs for scheduling details.')); 898 wp_send_json_success(array('message' => 'Automated posting enabled.')); 808 899 } else { 809 900 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 810 901 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 811 RSS2Post::log('Automated posting disabled and cron job rss2post_automated_12h_job cleared.', 'info'); 902 wp_clear_scheduled_hook('rss2post_automated_job'); 903 RSS2Post::log('Automated posting disabled and cron jobs cleared.', 'info'); 812 904 wp_send_json_success(array('message' => 'Automated posting disabled.')); 813 905 } 906 } 907 908 public function ajax_update_automated_settings() { 909 check_ajax_referer('rss2post_nonce', 'nonce'); 910 if (!current_user_can('manage_options')) { 911 wp_send_json_error(array('message' => 'Permission denied.')); 912 return; 913 } 914 915 $settings = get_option('rss2post_settings', array()); 916 917 $runs = isset($_POST['runs_per_day']) ? (int)$_POST['runs_per_day'] : 2; 918 if ($runs < 1) $runs = 1; 919 if ($runs > 10) $runs = 10; 920 921 $articles = isset($_POST['articles_per_day']) ? (int)$_POST['articles_per_day'] : 10; 922 if ($articles < 1) $articles = 1; 923 if ($articles > 10) $articles = 10; 924 925 $settings['runs_per_day'] = $runs; 926 $settings['articles_per_day'] = $articles; 927 update_option('rss2post_settings', $settings); 928 929 // If automation is enabled, reschedule to apply new interval 930 if (isset($settings['automated_posting_enabled']) && $settings['automated_posting_enabled']) { 931 wp_clear_scheduled_hook('rss2post_automated_job'); 932 wp_schedule_event(time(), 'rss2post_custom_schedule', 'rss2post_automated_job'); 933 RSS2Post::log("Rescheduled automated job due to settings change. Runs: {$runs}, Articles per day: {$articles}", 'info'); 934 } 935 936 wp_send_json_success(array('message' => 'Automation settings saved.')); 814 937 } 815 938 … … 1046 1169 } 1047 1170 1171 public function ajax_save_article_size() { 1172 check_ajax_referer('rss2post_nonce', 'nonce'); 1173 1174 if (!current_user_can('manage_options')) { 1175 wp_send_json_error(array('message' => 'Permission denied.')); 1176 return; 1177 } 1178 1179 $size = isset($_POST['article_size']) ? sanitize_text_field(wp_unslash($_POST['article_size'])) : ''; 1180 1181 if (empty($size)) { 1182 wp_send_json_error(array('message' => 'Article size is required.')); 1183 return; 1184 } 1185 1186 $valid_sizes = array('Small', 'Medium', 'Long'); 1187 if (!in_array($size, $valid_sizes)) { 1188 wp_send_json_error(array('message' => 'Invalid article size.')); 1189 return; 1190 } 1191 1192 $settings = get_option('rss2post_settings', array()); 1193 $settings['article_size'] = $size; 1194 update_option('rss2post_settings', $settings); 1195 1196 RSS2Post::log("Article size updated to: {$size}", 'info'); 1197 wp_send_json_success(array('message' => 'Article size saved successfully.')); 1198 } 1199 1048 1200 public function ajax_update_automated_feeds() { 1049 1201 check_ajax_referer('rss2post_nonce', 'nonce'); … … 1244 1396 1245 1397 $automated_posting_enabled = isset($settings['automated_posting_enabled']) ? (bool) $settings['automated_posting_enabled'] : false; 1398 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 1399 $articles_per_day = isset($settings['articles_per_day']) ? (int)$settings['articles_per_day'] : 10; 1246 1400 $user_credits = isset($settings['user_credits']) ? (int)$settings['user_credits'] : 10; 1247 1401 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 1402 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 1248 1403 1249 1404 $payment_status = null; … … 1489 1644 1490 1645 <div class="rss2post-section"> 1491 <h2>5. LanguageSettings</h2>1492 <p class="description"> Select the language for AI-generated content. This affects the language of titles, content, categories, and tags.</p>1646 <h2>5. Content Settings</h2> 1647 <p class="description">Configure the language and length of your AI-generated content.</p> 1493 1648 <table class="form-table"> 1494 1649 <tr> … … 1517 1672 <p class="description">Generated blog posts will be written in the selected language.</p> 1518 1673 <span id="language-save-feedback" style="margin-left: 10px;"></span> 1674 </td> 1675 </tr> 1676 <tr> 1677 <th><label for="article-size">Article Size</label></th> 1678 <td> 1679 <select id="article-size" name="article_size" class="regular-text"> 1680 <option value="Small" <?php selected($article_size, 'Small'); ?>>Small (Standard)</option> 1681 <option value="Medium" <?php selected($article_size, 'Medium'); ?>>Medium (2x Length)</option> 1682 <option value="Long" <?php selected($article_size, 'Long'); ?>>Long (3x Length)</option> 1683 </select> 1684 <p class="description">Choose the length of the generated articles.</p> 1685 <span id="article-size-save-feedback" style="margin-left: 10px;"></span> 1519 1686 </td> 1520 1687 </tr> … … 1581 1748 </td> 1582 1749 </tr> 1750 <tr class="automated-settings-row"> 1751 <th><label for="runs-per-day">Posting Frequency (Runs per day)</label></th> 1752 <td> 1753 <input type="number" id="runs-per-day" min="1" max="10" value="<?php echo esc_attr($runs_per_day); ?>" class="small-text" <?php disabled($user_tier === 'free'); ?>> 1754 <p class="description">How many times per day the automated posting job should run (Max 10).</p> 1755 </td> 1756 </tr> 1757 <tr class="automated-settings-row"> 1758 <th><label for="articles-per-day">Articles per Day</label></th> 1759 <td> 1760 <input type="number" id="articles-per-day" min="1" max="10" value="<?php echo esc_attr($articles_per_day); ?>" class="small-text" <?php disabled($user_tier === 'free'); ?>> 1761 <p class="description">Total articles to generate and post per day (Max 10). The plugin will automatically distribute these across your daily runs.</p> 1762 </td> 1763 </tr> 1764 <tr class="automated-settings-row"> 1765 <th></th> 1766 <td> 1767 <button type="button" id="save-automated-settings-button" class="button" <?php disabled($user_tier === 'free'); ?>>Save Automation Settings</button> 1768 <span id="save-automated-settings-feedback" style="margin-left: 10px;"></span> 1769 </td> 1770 </tr> 1583 1771 </table> 1584 1772 </div> … … 1921 2109 1922 2110 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 1923 2111 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 2112 2113 // Fetch all tags to send to backend to avoid creating new ones 2114 $all_site_tags = get_tags(array('hide_empty' => 0, 'fields' => 'names')); 2115 1924 2116 $data = array( 1925 2117 'pexels_api_key' => isset($settings['pexels_api_key']) ? $settings['pexels_api_key'] : '', … … 1932 2124 'available_categories' => $all_category_names, // All categories for content matching 1933 2125 'selected_categories' => $selected_category_names, // Mandatory categories from user selection 1934 'available_tags' => array(), // Tags are now handled by the backend2126 'available_tags' => $all_site_tags, // Send all existing tags 1935 2127 'content_language' => $content_language, 2128 'article_size' => $article_size, 1936 2129 'automated_tag_assign' => isset($settings['automated_tag_assign']) ? (bool)$settings['automated_tag_assign'] : false, 1937 2130 'auto_category_assign' => $auto_category_assign, -
rss-to-post-generator/tags/1.1.3/readme.txt
r3438914 r3441218 4 4 Requires at least: 5.6 5 5 Tested up to: 6.8 6 Stable tag: 1.1. 26 Stable tag: 1.1.3 7 7 License: GPLv2 or later 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 138 138 == Changelog == 139 139 140 = 1.1.3 = 141 * **Feature**: Added customizable automated posting frequency and article limits per day. 142 * **Feature**: Added article size option (Small, Medium, Long) for content generation. 143 * **Improvement**: Enhanced tag handling to use existing tags instead of creating new ones. 144 * **Improvement**: Automated posting now intelligently distributes articles throughout the day based on user settings. 145 140 146 = 1.1.2 = 141 147 * Resolved PHP fatal error due to function redeclaration. -
rss-to-post-generator/tags/1.1.3/rss2post.php
r3438914 r3441218 3 3 * Plugin Name: RSS to Post Generator 4 4 * Description: Generate blog posts from RSS feeds using AI content generation 5 * Version: 1.1. 25 * Version: 1.1.3 6 6 * Author: Samuel Bezerra Gomes 7 7 * License: GPL v2 or later … … 15 15 16 16 // Define plugin constants 17 define('RSS2POST_VERSION', '1.1. 2');17 define('RSS2POST_VERSION', '1.1.3'); 18 18 define('RSS2POST_PLUGIN_DIR', plugin_dir_path(__FILE__)); 19 19 define('RSS2POST_PLUGIN_URL', plugin_dir_url(__FILE__)); -
rss-to-post-generator/trunk/assets/js/admin.js
r3415485 r3441218 606 606 }); 607 607 608 // Handler for article size selection 609 $('#article-size').on('change', function() { 610 const size = $(this).val(); 611 const $feedbackSpan = $('#article-size-save-feedback'); 612 613 $feedbackSpan.text('Saving...').removeClass('success error').addClass('saving'); 614 615 $.ajax({ 616 url: rss2post_ajax.ajax_url, 617 type: 'POST', 618 data: { 619 action: 'rss2post_save_article_size', 620 nonce: rss2post_ajax.nonce, 621 article_size: size 622 }, 623 success: function(response) { 624 if (response.success) { 625 $feedbackSpan.text('Saved!').removeClass('saving error').addClass('success'); 626 } else { 627 $feedbackSpan.text('Error: ' + (response.data.message || 'Could not save.')).removeClass('saving success').addClass('error'); 628 } 629 }, 630 error: function() { 631 $feedbackSpan.text('Error: AJAX request failed.').removeClass('saving success').addClass('error'); 632 }, 633 complete: function() { 634 setTimeout(function() { 635 $feedbackSpan.text('').removeClass('saving success error'); 636 }, 3000); 637 } 638 }); 639 }); 640 608 641 $('#save-tags-button').on('click', function() { 609 642 const selectedTags = []; … … 741 774 }); 742 775 776 $('#runs-per-day, #articles-per-day').on('input', function() { 777 let val = $(this).val(); 778 // Allow empty string to let user clear and retype 779 if (val === '') return; 780 781 // Remove any non-digit characters 782 val = val.replace(/[^0-9]/g, ''); 783 784 let num = parseInt(val); 785 if (isNaN(num)) num = ''; 786 else if (num < 1) num = 1; 787 else if (num > 10) num = 10; 788 789 // Update value if it changed (handle strings vs numbers carefully) 790 if (val !== '' && num !== parseInt($(this).val())) { 791 $(this).val(num); 792 } else if (val !== $(this).val()) { 793 // Covers the case where non-digits were removed 794 $(this).val(val); 795 } 796 }); 797 798 // Ensure valid value on blur 799 $('#runs-per-day, #articles-per-day').on('blur', function() { 800 let val = parseInt($(this).val()); 801 if (isNaN(val) || val < 1) { 802 $(this).val(1); 803 } else if (val > 10) { 804 $(this).val(10); 805 } 806 }); 807 808 $('#save-automated-settings-button').on('click', saveAutomatedSettings); 809 743 810 $('input[name="image_source"]').on('change', function() { 744 811 if ($(this).val() === 'pexels') { … … 898 965 // The more complete one defined earlier in the file will be used. 899 966 967 function saveAutomatedSettings() { 968 const runsPerDay = parseInt($('#runs-per-day').val()) || 2; 969 const articlesPerDay = parseInt($('#articles-per-day').val()) || 10; 970 971 if (runsPerDay < 1 || runsPerDay > 10) { 972 alert('Runs per day must be between 1 and 10.'); 973 return; 974 } 975 if (articlesPerDay < 1 || articlesPerDay > 10) { 976 alert('Articles per day must be between 1 and 10.'); 977 return; 978 } 979 980 const $button = $('#save-automated-settings-button'); 981 const $feedback = $('#save-automated-settings-feedback'); 982 983 $button.prop('disabled', true).text('Saving...'); 984 $feedback.text('Saving...').removeClass('success error').addClass('saving'); 985 986 $.ajax({ 987 url: rss2post_ajax.ajax_url, 988 type: 'POST', 989 data: { 990 action: 'rss2post_update_automated_settings', 991 nonce: rss2post_ajax.nonce, 992 runs_per_day: runsPerDay, 993 articles_per_day: articlesPerDay 994 }, 995 success: function(response) { 996 if (response.success) { 997 $feedback.text('Settings saved!').removeClass('saving error').addClass('success'); 998 } else { 999 $feedback.text('Error: ' + (response.data.message || 'Could not save.')).removeClass('saving success').addClass('error'); 1000 } 1001 }, 1002 error: function() { 1003 $feedback.text('Error: Failed to save settings.').removeClass('saving success').addClass('error'); 1004 }, 1005 complete: function() { 1006 $button.prop('disabled', false).text('Save Automation Settings'); 1007 setTimeout(function() { 1008 $feedback.text('').removeClass('saving success error'); 1009 }, 3000); 1010 } 1011 }); 1012 } 1013 900 1014 function toggleAutomatedPosting() { 901 1015 const isEnabled = $(this).is(':checked'); 902 1016 const feeds = $('#rss-feeds').val().trim(); 1017 const runsPerDay = parseInt($('#runs-per-day').val()) || 2; 1018 const articlesPerDay = parseInt($('#articles-per-day').val()) || 10; 903 1019 904 1020 if (userTier !== 'pro' && userTier !== 'lifetime' && isEnabled) { … … 911 1027 if (!feeds) { 912 1028 alert('Please enter at least one RSS feed URL in the "RSS Feed URLs" section before enabling automated posting.'); 1029 $(this).prop('checked', false); 1030 return; 1031 } 1032 if (articlesPerDay > 10) { 1033 alert('The maximum amount of generation + posts is 10 per day.'); 913 1034 $(this).prop('checked', false); 914 1035 return; … … 932 1053 enabled: isEnabled, 933 1054 feeds: feeds, 1055 runs_per_day: runsPerDay, 1056 articles_per_day: articlesPerDay, 934 1057 current_username: $('#wp-username').val().trim(), 935 1058 current_password: $('#wp-password').val().trim() -
rss-to-post-generator/trunk/includes/class-admin.php
r3438847 r3441218 16 16 add_action('rss2post_automated_hourly_job', array($this, 'do_automated_posting_job')); // Retained in case it's a valid, albeit unused, hook for some users 17 17 add_action('rss2post_automated_12h_job', array($this, 'do_automated_posting_job')); 18 add_action('rss2post_automated_job', array($this, 'do_automated_posting_job')); 18 19 add_action('wp_ajax_rss2post_save_credentials', array($this, 'ajax_save_credentials')); 19 20 add_action('wp_ajax_rss2post_save_language', array($this, 'ajax_save_language')); 21 add_action('wp_ajax_rss2post_save_article_size', array($this, 'ajax_save_article_size')); 20 22 add_action('wp_ajax_rss2post_update_automated_feeds', array($this, 'ajax_update_automated_feeds')); 23 add_action('wp_ajax_rss2post_update_automated_settings', array($this, 'ajax_update_automated_settings')); 21 24 add_action('wp_ajax_rss2post_create_stripe_checkout', array($this, 'ajax_create_stripe_checkout')); 22 25 add_action('wp_ajax_rss2post_verify_payment', array($this, 'ajax_verify_payment_and_upgrade')); … … 30 33 add_action('wp_ajax_rss2post_save_api_keys', array($this, 'ajax_save_api_keys')); 31 34 add_action('rss2post_daily_subscription_check', array($this, 'check_all_pro_subscriptions')); 35 add_filter('cron_schedules', array($this, 'add_custom_cron_schedules')); 32 36 33 37 if (!wp_next_scheduled('rss2post_daily_subscription_check')) { 34 38 wp_schedule_event(time(), 'daily', 'rss2post_daily_subscription_check'); 35 39 } 40 } 41 42 public function add_custom_cron_schedules($schedules) { 43 $settings = get_option('rss2post_settings', array()); 44 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 45 if ($runs_per_day < 1) $runs_per_day = 1; 46 if ($runs_per_day > 10) $runs_per_day = 10; 47 48 $interval = 86400 / $runs_per_day; 49 50 $schedules['rss2post_custom_schedule'] = array( 51 'interval' => $interval, 52 'display' => "Every {$interval} seconds (RSS2Post Custom)" 53 ); 54 return $schedules; 36 55 } 37 56 … … 412 431 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 413 432 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 433 wp_clear_scheduled_hook('rss2post_automated_job'); 414 434 return; 415 435 } … … 419 439 return; 420 440 } 441 442 // --- New Distribution Logic Start --- 443 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 444 $articles_per_day = isset($settings['articles_per_day']) ? (int)$settings['articles_per_day'] : 10; 445 446 // Load daily stats 447 $daily_stats = get_option('rss2post_daily_stats', array( 448 'date' => '', 449 'runs_completed' => 0, 450 'articles_posted' => 0 451 )); 452 453 $current_date = current_time('Y-m-d'); 454 455 // Reset stats if new day 456 if ($daily_stats['date'] !== $current_date) { 457 RSS2Post::log("New day detected (Old: {$daily_stats['date']}, New: {$current_date}). Resetting daily stats.", 'info'); 458 $daily_stats = array( 459 'date' => $current_date, 460 'runs_completed' => 0, 461 'articles_posted' => 0 462 ); 463 } 464 465 // Check limits 466 if ($daily_stats['runs_completed'] >= $runs_per_day) { 467 RSS2Post::log("Daily run limit reached ({$daily_stats['runs_completed']}/{$runs_per_day}). Job exiting.", 'info'); 468 return; 469 } 470 471 if ($daily_stats['articles_posted'] >= $articles_per_day) { 472 RSS2Post::log("Daily article limit reached ({$daily_stats['articles_posted']}/{$articles_per_day}). Job exiting.", 'info'); 473 // We still increment runs_completed to keep the schedule "ticking" correctly relative to the day? 474 // Actually, if we skip because of article limit, we effectively consume a run slot without posting. 475 $daily_stats['runs_completed']++; 476 update_option('rss2post_daily_stats', $daily_stats); 477 return; 478 } 479 480 // Calculate articles for this run 481 $remaining_runs = $runs_per_day - $daily_stats['runs_completed']; 482 // Safety check to avoid division by zero (though runs_completed check above should prevent this) 483 if ($remaining_runs <= 0) $remaining_runs = 1; 484 485 $remaining_articles = $articles_per_day - $daily_stats['articles_posted']; 486 if ($remaining_articles < 0) $remaining_articles = 0; 487 488 // Distribute remaining articles over remaining runs (ceil ensures we don't under-post) 489 $articles_to_post_now = (int) ceil($remaining_articles / $remaining_runs); 490 491 RSS2Post::log("Run #{$daily_stats['runs_completed']} of {$runs_per_day}. Posted today: {$daily_stats['articles_posted']}/{$articles_per_day}. Planning to post {$articles_to_post_now} articles.", 'info'); 492 493 if ($articles_to_post_now <= 0) { 494 $daily_stats['runs_completed']++; 495 update_option('rss2post_daily_stats', $daily_stats); 496 return; 497 } 498 499 $max_articles_per_run = $articles_to_post_now; 500 // --- New Distribution Logic End --- 421 501 422 502 $automated_feeds = isset($settings['automated_rss_feeds']) && is_array($settings['automated_rss_feeds']) ? $settings['automated_rss_feeds'] : array(); … … 550 630 // Step 2: Round-robin distribution across feeds 551 631 $articles_to_post = array(); 552 $max_articles_per_run = 6; // Maximum total articles to post per run632 // $max_articles_per_run is set above based on daily distribution 553 633 $posted_count = 0; 554 634 $feed_indices = array(); … … 594 674 // Step 3: Post the selected articles and track which feeds successfully posted 595 675 $successfully_posted_by_feed = array(); // Track successful posts per feed 676 $actually_posted_count = 0; 596 677 597 678 foreach ($articles_to_post as $single_article_to_post) { … … 602 683 603 684 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 685 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 604 686 605 687 $data_for_api = array( … … 615 697 'available_tags' => $all_site_tags, 616 698 'content_language' => $content_language, 699 'article_size' => $article_size, 617 700 'automated_tag_assign' => isset($settings['automated_tag_assign']) ? (bool)$settings['automated_tag_assign'] : false, 618 701 'auto_category_assign' => $auto_category_assign, … … 658 741 } 659 742 $successfully_posted_by_feed[$feed_url_key][] = $single_article_to_post['original_guid']; 743 $actually_posted_count++; 660 744 } 661 745 } else { … … 665 749 wp_cache_delete('alloptions', 'options'); 666 750 } 751 752 // Update stats 753 $daily_stats['runs_completed']++; 754 $daily_stats['articles_posted'] += $actually_posted_count; 755 update_option('rss2post_daily_stats', $daily_stats); 756 RSS2Post::log("Stats updated. Runs: {$daily_stats['runs_completed']}, Articles posted today: {$daily_stats['articles_posted']}", 'info'); 667 757 668 758 // Step 4: Update last processed GUIDs ONLY for feeds that successfully posted articles … … 699 789 } 700 790 $new_status = isset($_POST['enabled']) && sanitize_text_field(wp_unslash($_POST['enabled'])) === 'true'; 791 792 // Save frequency and articles settings if provided 793 if (isset($_POST['runs_per_day'])) { 794 $runs = (int) $_POST['runs_per_day']; 795 if ($runs < 1) $runs = 1; 796 if ($runs > 10) $runs = 10; 797 $settings['runs_per_day'] = $runs; 798 } 799 800 if (isset($_POST['articles_per_day'])) { 801 $articles = (int) $_POST['articles_per_day']; 802 if ($articles < 1) $articles = 1; 803 if ($articles > 10) $articles = 10; 804 $settings['articles_per_day'] = $articles; 805 } 701 806 702 807 // Always update feeds when toggling (both enabling and re-enabling) … … 771 876 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 772 877 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 878 wp_clear_scheduled_hook('rss2post_automated_job'); 773 879 774 880 RSS2Post::log('Running automated posting job immediately upon enabling.', 'info'); … … 780 886 } 781 887 782 RSS2Post::log('Attempting to schedule rss2post_automated_12h_job.', 'info'); 783 if (!wp_next_scheduled('rss2post_automated_12h_job')) { 784 RSS2Post::log('No existing rss2post_automated_12h_job found. Proceeding to schedule.', 'info'); 785 // Schedule the first run for a short time from now to make testing easier, then 'twicedaily' will take over. 786 // Or, use time() if the first run should be in 12 hours. 787 // For testing visibility, let's schedule it for 1 minute from now. 788 // $first_run_time = time() + 60; // For quick testing 789 // For production, it should align with 'twicedaily' logic, so time() is fine, WP handles the first run based on 'twicedaily'. 790 $scheduled = wp_schedule_event(time(), 'twicedaily', 'rss2post_automated_12h_job'); 888 RSS2Post::log('Attempting to schedule rss2post_automated_job.', 'info'); 889 if (!wp_next_scheduled('rss2post_automated_job')) { 890 $scheduled = wp_schedule_event(time(), 'rss2post_custom_schedule', 'rss2post_automated_job'); 791 891 if ($scheduled === false) { 792 RSS2Post::log('wp_schedule_event for rss2post_automated_ 12h_job FAILED.', 'error');892 RSS2Post::log('wp_schedule_event for rss2post_automated_job FAILED.', 'error'); 793 893 } else { 794 RSS2Post::log('wp_schedule_event for rss2post_automated_12h_job SUCCEEDED. Check cron tools.', 'info'); 795 } 796 } else { 797 RSS2Post::log('rss2post_automated_12h_job is already scheduled. Next run at timestamp: ' . wp_next_scheduled('rss2post_automated_12h_job'), 'info'); 894 RSS2Post::log('wp_schedule_event for rss2post_automated_job SUCCEEDED with rss2post_custom_schedule.', 'info'); 895 } 798 896 } 799 897 800 // Let's get the event details again after attempting to schedule 801 $event_after_schedule = wp_get_scheduled_event('rss2post_automated_12h_job'); 802 if ($event_after_schedule) { 803 RSS2Post::log('Verification with wp_get_scheduled_event for rss2post_automated_12h_job: Hook=' . $event_after_schedule->hook . ', Timestamp=' . $event_after_schedule->timestamp . ' (Next run: ' . get_date_from_gmt(gmdate('Y-m-d H:i:s', $event_after_schedule->timestamp), 'Y-m-d H:i:s') . '), Schedule=' . $event_after_schedule->schedule, 'info'); 804 } else { 805 RSS2Post::log('Verification with wp_get_scheduled_event for rss2post_automated_12h_job: No event found. This is unexpected if scheduling succeeded.', 'error'); 806 } 807 wp_send_json_success(array('message' => 'Automated posting enabled. Please check your WordPress cron events list and debug logs for scheduling details.')); 898 wp_send_json_success(array('message' => 'Automated posting enabled.')); 808 899 } else { 809 900 wp_clear_scheduled_hook('rss2post_automated_hourly_job'); 810 901 wp_clear_scheduled_hook('rss2post_automated_12h_job'); 811 RSS2Post::log('Automated posting disabled and cron job rss2post_automated_12h_job cleared.', 'info'); 902 wp_clear_scheduled_hook('rss2post_automated_job'); 903 RSS2Post::log('Automated posting disabled and cron jobs cleared.', 'info'); 812 904 wp_send_json_success(array('message' => 'Automated posting disabled.')); 813 905 } 906 } 907 908 public function ajax_update_automated_settings() { 909 check_ajax_referer('rss2post_nonce', 'nonce'); 910 if (!current_user_can('manage_options')) { 911 wp_send_json_error(array('message' => 'Permission denied.')); 912 return; 913 } 914 915 $settings = get_option('rss2post_settings', array()); 916 917 $runs = isset($_POST['runs_per_day']) ? (int)$_POST['runs_per_day'] : 2; 918 if ($runs < 1) $runs = 1; 919 if ($runs > 10) $runs = 10; 920 921 $articles = isset($_POST['articles_per_day']) ? (int)$_POST['articles_per_day'] : 10; 922 if ($articles < 1) $articles = 1; 923 if ($articles > 10) $articles = 10; 924 925 $settings['runs_per_day'] = $runs; 926 $settings['articles_per_day'] = $articles; 927 update_option('rss2post_settings', $settings); 928 929 // If automation is enabled, reschedule to apply new interval 930 if (isset($settings['automated_posting_enabled']) && $settings['automated_posting_enabled']) { 931 wp_clear_scheduled_hook('rss2post_automated_job'); 932 wp_schedule_event(time(), 'rss2post_custom_schedule', 'rss2post_automated_job'); 933 RSS2Post::log("Rescheduled automated job due to settings change. Runs: {$runs}, Articles per day: {$articles}", 'info'); 934 } 935 936 wp_send_json_success(array('message' => 'Automation settings saved.')); 814 937 } 815 938 … … 1046 1169 } 1047 1170 1171 public function ajax_save_article_size() { 1172 check_ajax_referer('rss2post_nonce', 'nonce'); 1173 1174 if (!current_user_can('manage_options')) { 1175 wp_send_json_error(array('message' => 'Permission denied.')); 1176 return; 1177 } 1178 1179 $size = isset($_POST['article_size']) ? sanitize_text_field(wp_unslash($_POST['article_size'])) : ''; 1180 1181 if (empty($size)) { 1182 wp_send_json_error(array('message' => 'Article size is required.')); 1183 return; 1184 } 1185 1186 $valid_sizes = array('Small', 'Medium', 'Long'); 1187 if (!in_array($size, $valid_sizes)) { 1188 wp_send_json_error(array('message' => 'Invalid article size.')); 1189 return; 1190 } 1191 1192 $settings = get_option('rss2post_settings', array()); 1193 $settings['article_size'] = $size; 1194 update_option('rss2post_settings', $settings); 1195 1196 RSS2Post::log("Article size updated to: {$size}", 'info'); 1197 wp_send_json_success(array('message' => 'Article size saved successfully.')); 1198 } 1199 1048 1200 public function ajax_update_automated_feeds() { 1049 1201 check_ajax_referer('rss2post_nonce', 'nonce'); … … 1244 1396 1245 1397 $automated_posting_enabled = isset($settings['automated_posting_enabled']) ? (bool) $settings['automated_posting_enabled'] : false; 1398 $runs_per_day = isset($settings['runs_per_day']) ? (int)$settings['runs_per_day'] : 2; 1399 $articles_per_day = isset($settings['articles_per_day']) ? (int)$settings['articles_per_day'] : 10; 1246 1400 $user_credits = isset($settings['user_credits']) ? (int)$settings['user_credits'] : 10; 1247 1401 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 1402 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 1248 1403 1249 1404 $payment_status = null; … … 1489 1644 1490 1645 <div class="rss2post-section"> 1491 <h2>5. LanguageSettings</h2>1492 <p class="description"> Select the language for AI-generated content. This affects the language of titles, content, categories, and tags.</p>1646 <h2>5. Content Settings</h2> 1647 <p class="description">Configure the language and length of your AI-generated content.</p> 1493 1648 <table class="form-table"> 1494 1649 <tr> … … 1517 1672 <p class="description">Generated blog posts will be written in the selected language.</p> 1518 1673 <span id="language-save-feedback" style="margin-left: 10px;"></span> 1674 </td> 1675 </tr> 1676 <tr> 1677 <th><label for="article-size">Article Size</label></th> 1678 <td> 1679 <select id="article-size" name="article_size" class="regular-text"> 1680 <option value="Small" <?php selected($article_size, 'Small'); ?>>Small (Standard)</option> 1681 <option value="Medium" <?php selected($article_size, 'Medium'); ?>>Medium (2x Length)</option> 1682 <option value="Long" <?php selected($article_size, 'Long'); ?>>Long (3x Length)</option> 1683 </select> 1684 <p class="description">Choose the length of the generated articles.</p> 1685 <span id="article-size-save-feedback" style="margin-left: 10px;"></span> 1519 1686 </td> 1520 1687 </tr> … … 1581 1748 </td> 1582 1749 </tr> 1750 <tr class="automated-settings-row"> 1751 <th><label for="runs-per-day">Posting Frequency (Runs per day)</label></th> 1752 <td> 1753 <input type="number" id="runs-per-day" min="1" max="10" value="<?php echo esc_attr($runs_per_day); ?>" class="small-text" <?php disabled($user_tier === 'free'); ?>> 1754 <p class="description">How many times per day the automated posting job should run (Max 10).</p> 1755 </td> 1756 </tr> 1757 <tr class="automated-settings-row"> 1758 <th><label for="articles-per-day">Articles per Day</label></th> 1759 <td> 1760 <input type="number" id="articles-per-day" min="1" max="10" value="<?php echo esc_attr($articles_per_day); ?>" class="small-text" <?php disabled($user_tier === 'free'); ?>> 1761 <p class="description">Total articles to generate and post per day (Max 10). The plugin will automatically distribute these across your daily runs.</p> 1762 </td> 1763 </tr> 1764 <tr class="automated-settings-row"> 1765 <th></th> 1766 <td> 1767 <button type="button" id="save-automated-settings-button" class="button" <?php disabled($user_tier === 'free'); ?>>Save Automation Settings</button> 1768 <span id="save-automated-settings-feedback" style="margin-left: 10px;"></span> 1769 </td> 1770 </tr> 1583 1771 </table> 1584 1772 </div> … … 1921 2109 1922 2110 $content_language = isset($settings['content_language']) ? $settings['content_language'] : 'en'; 1923 2111 $article_size = isset($settings['article_size']) ? $settings['article_size'] : 'Small'; 2112 2113 // Fetch all tags to send to backend to avoid creating new ones 2114 $all_site_tags = get_tags(array('hide_empty' => 0, 'fields' => 'names')); 2115 1924 2116 $data = array( 1925 2117 'pexels_api_key' => isset($settings['pexels_api_key']) ? $settings['pexels_api_key'] : '', … … 1932 2124 'available_categories' => $all_category_names, // All categories for content matching 1933 2125 'selected_categories' => $selected_category_names, // Mandatory categories from user selection 1934 'available_tags' => array(), // Tags are now handled by the backend2126 'available_tags' => $all_site_tags, // Send all existing tags 1935 2127 'content_language' => $content_language, 2128 'article_size' => $article_size, 1936 2129 'automated_tag_assign' => isset($settings['automated_tag_assign']) ? (bool)$settings['automated_tag_assign'] : false, 1937 2130 'auto_category_assign' => $auto_category_assign, -
rss-to-post-generator/trunk/readme.txt
r3438914 r3441218 4 4 Requires at least: 5.6 5 5 Tested up to: 6.8 6 Stable tag: 1.1. 26 Stable tag: 1.1.3 7 7 License: GPLv2 or later 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 138 138 == Changelog == 139 139 140 = 1.1.3 = 141 * **Feature**: Added customizable automated posting frequency and article limits per day. 142 * **Feature**: Added article size option (Small, Medium, Long) for content generation. 143 * **Improvement**: Enhanced tag handling to use existing tags instead of creating new ones. 144 * **Improvement**: Automated posting now intelligently distributes articles throughout the day based on user settings. 145 140 146 = 1.1.2 = 141 147 * Resolved PHP fatal error due to function redeclaration. -
rss-to-post-generator/trunk/rss2post.php
r3438914 r3441218 3 3 * Plugin Name: RSS to Post Generator 4 4 * Description: Generate blog posts from RSS feeds using AI content generation 5 * Version: 1.1. 25 * Version: 1.1.3 6 6 * Author: Samuel Bezerra Gomes 7 7 * License: GPL v2 or later … … 15 15 16 16 // Define plugin constants 17 define('RSS2POST_VERSION', '1.1. 2');17 define('RSS2POST_VERSION', '1.1.3'); 18 18 define('RSS2POST_PLUGIN_DIR', plugin_dir_path(__FILE__)); 19 19 define('RSS2POST_PLUGIN_URL', plugin_dir_url(__FILE__));
Note: See TracChangeset
for help on using the changeset viewer.